[PATCH] D49945: [Fixed Point Arithmetic] Fix for FixedPointValueToString
leonardchan marked an inline comment as done. leonardchan added inline comments. Comment at: lib/AST/Expr.cpp:788 FixedPointValueToString( - S, llvm::APSInt::getUnsigned(getValue().getZExtValue()), Scale, Radix); + S, llvm::APSInt::getUnsigned(getValue().getZExtValue()), Scale); return S.str(); ebevhan wrote: > Unrelated to this patch specifically, but using `getZExtValue` here is a bit > limiting. I'll make another small patch to change this since should also do signed values now, Repository: rC Clang https://reviews.llvm.org/D49945 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D49945: [Fixed Point Arithmetic] Fix for FixedPointValueToString
This revision was automatically updated to reflect the committed changes. leonardchan marked an inline comment as done. Closed by commit rC339026: [Fixed Point Arithmetic] Fix for FixedPointValueToString (authored by leonardchan, committed by ). Repository: rC Clang https://reviews.llvm.org/D49945 Files: include/clang/AST/Type.h lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/AST/Type.cpp test/Frontend/fixed_point_to_string.c unittests/Frontend/CMakeLists.txt unittests/Frontend/FixedPointString.cpp Index: test/Frontend/fixed_point_to_string.c === --- test/Frontend/fixed_point_to_string.c +++ test/Frontend/fixed_point_to_string.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -ast-dump -ffixed-point %s | FileCheck %s +// RUN: %clang_cc1 -ast-dump -ffixed-point -fpadding-on-unsigned-fixed-point %s | FileCheck %s + +/** + * Check the same values are printed in the AST regardless of if unsigned types + * have the same number of fractional bits as signed types. + */ + +unsigned short _Accum u_short_accum = 0.5uhk; +unsigned _Accum u_accum = 0.5uk; +unsigned long _Accum u_long_accum = 0.5ulk; +unsigned short _Fract u_short_fract = 0.5uhr; +unsigned _Fract u_fract = 0.5ur; +unsigned long _Fract u_long_fract = 0.5ulr; + +//CHECK: FixedPointLiteral {{.*}} 'unsigned short _Accum' 0.5 +//CHECK: FixedPointLiteral {{.*}} 'unsigned _Accum' 0.5 +//CHECK: FixedPointLiteral {{.*}} 'unsigned long _Accum' 0.5 +//CHECK: FixedPointLiteral {{.*}} 'unsigned short _Fract' 0.5 +//CHECK: FixedPointLiteral {{.*}} 'unsigned _Fract' 0.5 +//CHECK: FixedPointLiteral {{.*}} 'unsigned long _Fract' 0.5 Index: lib/AST/Type.cpp === --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -4032,17 +4032,26 @@ } void clang::FixedPointValueToString(SmallVectorImpl &Str, -const llvm::APSInt &Val, unsigned Scale, -unsigned Radix) { - llvm::APSInt ScaleVal = llvm::APSInt::getUnsigned(1ULL << Scale); - llvm::APSInt IntPart = Val / ScaleVal; - llvm::APSInt FractPart = Val % ScaleVal; - llvm::APSInt RadixInt = llvm::APSInt::getUnsigned(Radix); +llvm::APSInt Val, unsigned Scale) { + if (Val.isSigned() && Val.isNegative() && Val != -Val) { +Val = -Val; +Str.push_back('-'); + } + + llvm::APSInt IntPart = Val >> Scale; + + // Add 4 digits to hold the value after multiplying 10 (the radix) + unsigned Width = Val.getBitWidth() + 4; + llvm::APInt FractPart = Val.zextOrTrunc(Scale).zext(Width); + llvm::APInt FractPartMask = llvm::APInt::getAllOnesValue(Scale).zext(Width); + llvm::APInt RadixInt = llvm::APInt(Width, 10); - IntPart.toString(Str, Radix); + IntPart.toString(Str, /*radix=*/10); Str.push_back('.'); do { -(FractPart * RadixInt / ScaleVal).toString(Str, Radix); -FractPart = (FractPart * RadixInt) % ScaleVal; - } while (FractPart.getExtValue()); +(FractPart * RadixInt) +.lshr(Scale) +.toString(Str, /*radix=*/10, Val.isSigned()); +FractPart = (FractPart * RadixInt) & FractPartMask; + } while (FractPart != 0); } Index: lib/AST/Expr.cpp === --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -785,7 +785,7 @@ // which is 43 characters. SmallString<64> S; FixedPointValueToString( - S, llvm::APSInt::getUnsigned(getValue().getZExtValue()), Scale, Radix); + S, llvm::APSInt::getUnsigned(getValue().getZExtValue()), Scale); return S.str(); } Index: lib/AST/ExprConstant.cpp === --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -9698,8 +9698,7 @@ if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow()) { SmallString<64> S; FixedPointValueToString(S, Value, -Info.Ctx.getTypeInfo(E->getType()).Width, -/*Radix=*/10); +Info.Ctx.getTypeInfo(E->getType()).Width); Info.CCEDiag(E, diag::note_constexpr_overflow) << S << E->getType(); if (Info.noteUndefinedBehavior()) return false; } Index: unittests/Frontend/FixedPointString.cpp === --- unittests/Frontend/FixedPointString.cpp +++ unittests/Frontend/FixedPointString.cpp @@ -0,0 +1,107 @@ +#include "clang/AST/Type.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallString.h" +#include "gtest/gtest.h" + +using clang::FixedPointValueToString; +using llvm::APSInt; +using llvm::SmallString; + +namespace { + +TEST(FixedPointString, DifferentTypes) { + SmallString<64> S; + FixedPointValueToString(S, APSInt::get(320), 7); + ASSERT_STREQ(S.c_str(), "2.5"); + + S.clear(); + FixedPointValueToString(S, APSInt::get(0), 7); + ASSERT_STREQ(S.c_str(), "0.0")
[PATCH] D50278: [Sema] Fix for crash on conditional operation with address_space pointer
leonardchan updated this revision to Diff 159315. leonardchan added reviewers: ebevhan, rjmccall. leonardchan removed a subscriber: ebevhan. leonardchan added a comment. - Changed diff such that an error is dumped instead. The code shouldn't compile in the first place since it involves conversion between pointers from different address_spaces. Repository: rC Clang https://reviews.llvm.org/D50278 Files: lib/Sema/SemaExpr.cpp test/Sema/address_spaces.c test/Sema/conditional-expr.c Index: test/Sema/conditional-expr.c === --- test/Sema/conditional-expr.c +++ test/Sema/conditional-expr.c @@ -74,9 +74,12 @@ int __attribute__((address_space(2))) *adr2; int __attribute__((address_space(3))) *adr3; test0 ? adr2 : adr3; // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + // expected-error@-1{{converting '__attribute__((address_space(2))) int *' to type 'void *' changes address space of pointer}} + // expected-error@-2{{converting '__attribute__((address_space(3))) int *' to type 'void *' changes address space of pointer}} // Make sure address-space mask ends up in the result type (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + // expected-error@-1{{converting '__attribute__((address_space(2))) int *' to type 'void *' changes address space of pointer}} } int Postgresql() { Index: test/Sema/address_spaces.c === --- test/Sema/address_spaces.c +++ test/Sema/address_spaces.c @@ -72,4 +72,6 @@ // Clang extension doesn't forbid operations on pointers to different address spaces. char* cmp(_AS1 char *x, _AS2 char *y) { return x < y ? x : y; // expected-warning {{pointer type mismatch ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *')}} +// expected-error@-1{{converting '__attribute__((address_space(1))) char *' to type 'void *' changes address space of pointer}} +// expected-error@-2{{converting '__attribute__((address_space(2))) char *' to type 'void *' changes address space of pointer}} } Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -6527,6 +6527,21 @@ S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + +// If the addresse spacesare different, we do not allow a bitcast. +if (!S.getLangOpts().OpenCL) { + if (LAddrSpace != ResultAddrSpace) { +S.Diag(Loc, diag::err_typecheck_incompatible_address_space) +<< LHSTy << incompatTy << Sema::AA_Converting +<< LHS.get()->getSourceRange(); + } + if (RAddrSpace != ResultAddrSpace) { +S.Diag(Loc, diag::err_typecheck_incompatible_address_space) +<< RHSTy << incompatTy << Sema::AA_Converting +<< RHS.get()->getSourceRange(); + } +} + return incompatTy; } Index: test/Sema/conditional-expr.c === --- test/Sema/conditional-expr.c +++ test/Sema/conditional-expr.c @@ -74,9 +74,12 @@ int __attribute__((address_space(2))) *adr2; int __attribute__((address_space(3))) *adr3; test0 ? adr2 : adr3; // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + // expected-error@-1{{converting '__attribute__((address_space(2))) int *' to type 'void *' changes address space of pointer}} + // expected-error@-2{{converting '__attribute__((address_space(3))) int *' to type 'void *' changes address space of pointer}} // Make sure address-space mask ends up in the result type (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + // expected-error@-1{{converting '__attribute__((address_space(2))) int *' to type 'void *' changes address space of pointer}} } int Postgresql() { Index: test/Sema/address_spaces.c === --- test/Sema/address_spaces.c +++ test/Sema/address_spaces.c @@ -72,4 +72,6 @@ // Clang extension doesn't forbid operations on pointers to different address spaces. char* cmp(_AS1 char *x, _AS2 char *y) { return x < y ? x : y; // expected-warning {{pointer type mismatch ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *')}} +// expected-error@-1{{converting '_
[PATCH] D48661: [Fixed Point Arithmetic] Fixed Point Constant
leonardchan updated this revision to Diff 159320. leonardchan marked an inline comment as done. leonardchan added a comment. - Fixed `Accumum` names Repository: rC Clang https://reviews.llvm.org/D48661 Files: include/clang/AST/ASTContext.h include/clang/Basic/FixedPoint.h include/clang/Basic/TargetInfo.h lib/AST/ASTContext.cpp lib/Basic/CMakeLists.txt lib/Basic/FixedPoint.cpp lib/Sema/SemaExpr.cpp test/Frontend/fixed_point_declarations.c unittests/Basic/CMakeLists.txt unittests/Basic/FixedPointTest.cpp Index: unittests/Basic/FixedPointTest.cpp === --- /dev/null +++ unittests/Basic/FixedPointTest.cpp @@ -0,0 +1,683 @@ +//===- unittests/Basic/FixedPointTest.cpp -- fixed point number tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "clang/Basic/FixedPoint.h" +#include "llvm/ADT/APSInt.h" +#include "gtest/gtest.h" + +using clang::APFixedPoint; +using clang::FixedPointSemantics; +using llvm::APInt; +using llvm::APSInt; + +namespace { + +FixedPointSemantics Saturated(FixedPointSemantics Sema) { + Sema.setSaturated(true); + return Sema; +} + +FixedPointSemantics getSAccumSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getAccumSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getLAccumSema() { + return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getSFractSema() { + return FixedPointSemantics(/*width=*/8, /*scale=*/7, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getFractSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/15, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getLFractSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/31, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getUSAccumSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/8, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getUAccumSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/16, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getULAccumSema() { + return FixedPointSemantics(/*width=*/64, /*scale=*/32, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getUSFractSema() { + return FixedPointSemantics(/*width=*/8, /*scale=*/8, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getUFractSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/16, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getULFractSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/32, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getPadUSAccumSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/true); +} + +FixedPointSemantics getPadUAccumSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/true); +} + +FixedPointSemantics getPadULAccumSema() { + return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/true); +} + +FixedPointSemantics getPadUSFractSema() { + return FixedPointSemanti
[PATCH] D48661: [Fixed Point Arithmetic] Fixed Point Constant
This revision was not accepted when it landed; it landed in state "Needs Review". This revision was automatically updated to reflect the committed changes. Closed by commit rL339028: [Fixed Point Arithmetic] Fixed Point Constant (authored by leonardchan, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D48661?vs=159320&id=159321#toc Repository: rL LLVM https://reviews.llvm.org/D48661 Files: cfe/trunk/include/clang/AST/ASTContext.h cfe/trunk/include/clang/Basic/FixedPoint.h cfe/trunk/include/clang/Basic/TargetInfo.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/Basic/CMakeLists.txt cfe/trunk/lib/Basic/FixedPoint.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/Frontend/fixed_point_declarations.c cfe/trunk/unittests/Basic/CMakeLists.txt cfe/trunk/unittests/Basic/FixedPointTest.cpp Index: cfe/trunk/test/Frontend/fixed_point_declarations.c === --- cfe/trunk/test/Frontend/fixed_point_declarations.c +++ cfe/trunk/test/Frontend/fixed_point_declarations.c @@ -1,5 +1,4 @@ // RUN: %clang -ffixed-point -S -emit-llvm %s -o - --target=x86_64-linux | FileCheck %s -// RUN: %clang -ffixed-point -S -emit-llvm %s -o - --target=x86_64-scei-ps4-ubuntu-fast | FileCheck %s // Primary fixed point types signed short _Accum s_short_accum; // CHECK-DAG: @s_short_accum = {{.*}}global i16 0, align 2 @@ -111,3 +110,18 @@ unsigned short _Fract u_short_fract_eps = 0x1p-8uhr;// CHECK-DAG: @u_short_fract_eps = {{.*}}global i8 1, align 1 unsigned _Fract u_fract_eps = 0x1p-16ur;// CHECK-DAG: @u_fract_eps = {{.*}}global i16 1, align 2 unsigned long _Fract u_long_fract_eps = 0x1p-32ulr; // CHECK-DAG: @u_long_fract_eps = {{.*}}global i32 1, align 4 + +// Zero +short _Accum short_accum_zero= 0.0hk;// CHECK-DAG: @short_accum_zero = {{.*}}global i16 0, align 2 + _Accum accum_zero = 0.0k; // CHECK-DAG: @accum_zero = {{.*}}global i32 0, align 4 +long _Accum long_accum_zero = 0.0lk;// CHECK-DAG: @long_accum_zero = {{.*}}global i64 0, align 8 +unsigned short _Accum u_short_accum_zero = 0.0uhk; // CHECK-DAG: @u_short_accum_zero = {{.*}}global i16 0, align 2 +unsigned _Accum u_accum_zero= 0.0uk;// CHECK-DAG: @u_accum_zero = {{.*}}global i32 0, align 4 +unsigned long _Accum u_long_accum_zero = 0.0ulk; // CHECK-DAG: @u_long_accum_zero= {{.*}}global i64 0, align 8 + +short _Fract short_fract_zero= 0.0hr;// CHECK-DAG: @short_fract_zero = {{.*}}global i8 0, align 1 + _Fract fract_zero = 0.0r; // CHECK-DAG: @fract_zero = {{.*}}global i16 0, align 2 +long _Fract long_fract_zero = 0.0lr;// CHECK-DAG: @long_fract_zero = {{.*}}global i32 0, align 4 +unsigned short _Fract u_short_fract_zero = 0.0uhr; // CHECK-DAG: @u_short_fract_zero = {{.*}}global i8 0, align 1 +unsigned _Fract u_fract_zero= 0.0ur;// CHECK-DAG: @u_fract_zero = {{.*}}global i16 0, align 2 +unsigned long _Fract u_long_fract_zero = 0.0ulr; // CHECK-DAG: @u_long_fract_zero= {{.*}}global i32 0, align 4 Index: cfe/trunk/lib/AST/ASTContext.cpp === --- cfe/trunk/lib/AST/ASTContext.cpp +++ cfe/trunk/lib/AST/ASTContext.cpp @@ -48,6 +48,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/CommentOptions.h" #include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/FixedPoint.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -10433,3 +10434,22 @@ return 0; } } + +FixedPointSemantics ASTContext::getFixedPointSemantics(QualType Ty) const { + assert(Ty->isFixedPointType()); + bool isSigned = Ty->isSignedFixedPointType(); + return FixedPointSemantics( + static_cast(getTypeSize(Ty)), getFixedPointScale(Ty), isSigned, + Ty->isSaturatedFixedPointType(), + !isSigned && getTargetInfo().doUnsignedFixedPointTypesHavePadding()); +} + +APFixedPoint ASTContext::getFixedPointMax(QualType Ty) const { + assert(Ty->isFixedPointType()); + return APFixedPoint::getMax(getFixedPointSemantics(Ty)); +} + +APFixedPoint ASTContext::getFixedPointMin(QualType Ty) const { + assert(Ty->isFixedPointType()); + return APFixedPoint::getMin(getFixedPointSemantics(Ty)); +} Index: cfe/trunk/lib/Sema/SemaExpr.cpp === --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -26,6 +26,7 @@ #include "clang/AST/ExprOpenMP.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/FixedPoint.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "cla
[PATCH] D48661: [Fixed Point Arithmetic] Fixed Point Constant
leonardchan added a comment. In https://reviews.llvm.org/D48661#1189537, @bricci wrote: > Just a nit but could you please add new-lines to your commit messages. My bad, will remember this for future commits. > Also the 3 bools in FixedPointSemantics are a little bit wasteful. > I don't know here if it matter but I have been spending the last weeks > cleaning up this kind of thing and this already cut the time of an > fsyntax-only > by ~3.5%. Would you recommend something along the lines of having a bitmask instead of 3 bools? What should I keep in mind to avoid making fsyntax-only longer? > And using the name Sema is a bad idea IMHO since this has a totally different > meaning in clang. I'll make another small patch where I rename this. Repository: rL LLVM https://reviews.llvm.org/D48661 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50278: [Sema] Fix for crash on conditional operation with address_space pointer
leonardchan added a comment. In https://reviews.llvm.org/D50278#1189919, @rjmccall wrote: > I would expect this to replace the existing warning, not to appear together > with it. Will do. Comment at: test/Sema/conditional-expr.c:78 + // expected-error@-1{{converting '__attribute__((address_space(2))) int *' to type 'void *' changes address space of pointer}} + // expected-error@-2{{converting '__attribute__((address_space(3))) int *' to type 'void *' changes address space of pointer}} rjmccall wrote: > Also, these diagnostics seem wrong. Where is `void *` coming from? When dumping the AST this is what the resulting type is for the conditional expression already is if the operands are 2 pointers with different address spaces. According to this comment, the reason seems to be because this is what GCC does: ``` 6512 // In this situation, we assume void* type. No especially good 6513 // reason, but this is what gcc does, and we do have to pick 6514 // to get a consistent AST. ``` Repository: rC Clang https://reviews.llvm.org/D50278 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50278: [Sema] Fix for crash on conditional operation with address_space pointer
leonardchan updated this revision to Diff 159405. leonardchan marked an inline comment as done. leonardchan added a comment. - Replaced instances of a `pointer type mismatch` warning involving 2 conditional operands with different address spaces with a new error specifically for this situation. Repository: rC Clang https://reviews.llvm.org/D50278 Files: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaExpr.cpp test/Sema/address_spaces.c test/Sema/conditional-expr.c Index: test/Sema/conditional-expr.c === --- test/Sema/conditional-expr.c +++ test/Sema/conditional-expr.c @@ -73,10 +73,12 @@ int __attribute__((address_space(2))) *adr2; int __attribute__((address_space(3))) *adr3; - test0 ? adr2 : adr3; // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + test0 ? adr2 : adr3; // expected-warning {{expression result unused}} + // expected-error@-1{{unable to find common type between '__attribute__((address_space(2))) int *' and '__attribute__((address_space(3))) int *' for conditional operation}} // Make sure address-space mask ends up in the result type - (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-warning {{expression result unused}} + // expected-error@-1{{unable to find common type between '__attribute__((address_space(2))) int *' and 'int *' for conditional operation}} } int Postgresql() { Index: test/Sema/address_spaces.c === --- test/Sema/address_spaces.c +++ test/Sema/address_spaces.c @@ -71,5 +71,5 @@ // Clang extension doesn't forbid operations on pointers to different address spaces. char* cmp(_AS1 char *x, _AS2 char *y) { - return x < y ? x : y; // expected-warning {{pointer type mismatch ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *')}} + return x < y ? x : y; // expected-error{{unable to find common type between '__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *' for conditional operation}} } Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -6517,16 +6517,29 @@ S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace)); LHS = S.ImpCastExprToType(LHS.get(), incompatTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), incompatTy, RHSCastKind); -// FIXME: For OpenCL the warning emission and cast to void* leaves a room -// for casts between types with incompatible address space qualifiers. -// For the following code the compiler produces casts between global and -// local address spaces of the corresponded innermost pointees: -// local int *global *a; -// global int *global *b; -// a = (0 ? a : b); // see C99 6.5.16.1.p1. -S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) -<< LHSTy << RHSTy << LHS.get()->getSourceRange() -<< RHS.get()->getSourceRange(); + +bool HasDifferingLAddrSpace = LAddrSpace != ResultAddrSpace; +bool HasDifferingRAddrSpace = RAddrSpace != ResultAddrSpace; + +if (S.getLangOpts().OpenCL || +!(HasDifferingLAddrSpace || HasDifferingRAddrSpace)) { + // FIXME: For OpenCL the warning emission and cast to void* leaves a room + // for casts between types with incompatible address space qualifiers. + // For the following code the compiler produces casts between global and + // local address spaces of the corresponded innermost pointees: + // local int *global *a; + // global int *global *b; + // a = (0 ? a : b); // see C99 6.5.16.1.p1. + S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); +} else { + // If the addresse spacesare different, we do not allow a bitcast. + S.Diag(Loc, diag::err_typecheck_incompatible_conditional_pointer_operands) + << LHSTy << RHSTy << Sema::AA_Converting + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); +} + return incompatTy; } Index: include/clang/Basic/DiagnosticSemaKinds.td === --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6939,6 +6939,8 @@ " changes retain/release properties of pointer">; def err_typecheck_comparison_of_distinct_blocks : Error< "comparison of distinct block types%diff{ ($ and $)|}0,1">; +def err_typecheck_incompatible_conditional_pointer_operands : Error< + "unable
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan updated this revision to Diff 159409. leonardchan marked 3 inline comments as done. leonardchan added a comment. - Changed tick to single quote in diagnostic Repository: rC Clang https://reviews.llvm.org/D49511 Files: include/clang/AST/Type.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/Type.cpp lib/AST/TypePrinter.cpp lib/Parse/ParseExpr.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprMember.cpp lib/Sema/SemaType.cpp test/Frontend/noderef.c test/Frontend/noderef_on_non_pointers.cpp test/Frontend/noderef_on_non_pointers.m Index: test/Frontend/noderef_on_non_pointers.m === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.m @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +#define NODEREF __attribute__((noderef)) + +@interface NSObject ++ (id)new; +@end + +void func() { + id NODEREF obj = [NSObject new]; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} Index: test/Frontend/noderef_on_non_pointers.cpp === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -fblocks -verify %s + +/** + * Test 'noderef' attribute against other pointer-like types. + */ + +#define NODEREF __attribute__((noderef)) + +void Normal() { + int NODEREF i;// expected-warning{{'noderef' can only be used on an array or pointer type}} + int NODEREF *i_ptr; // ok + int NODEREF **i_ptr2; // ok + int *NODEREF i_ptr3; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *NODEREF *i_ptr4; // ok + + auto NODEREF *auto_i_ptr = i_ptr; + auto NODEREF auto_i = i; // expected-warning{{'noderef' can only be used on an array or pointer type}} + + struct { +int x; +int y; + } NODEREF *s; + + int __attribute__((noderef(10))) * no_args; // expected-error{{'noderef' attribute takes no arguments}} +} + +const int NODEREF *const_i_ptr; +static int NODEREF *static_i_ptr; + +void ParenTypes() { + int NODEREF(*i_ptr);// ok (same as `int NODEREF *`) + int NODEREF *(*i_ptr2); // ok (same as `int NODEREF **`) +} + +// Function declarations +int NODEREF func(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +int NODEREF *func2(); // ok (returning pointer) + +typedef int NODEREF (*func3)(int); // expected-warning{{'noderef' can only be used on an array or pointer type}} +typedef int NODEREF *(*func4)(int); + +void Arrays() { + int NODEREF i_arr[10]; // ok + int NODEREF i_arr2[10][10]; // ok + int NODEREF *i_arr3[10];// ok + int NODEREF i_arr4[] = {1, 2}; +} + +void ParenArrays() { + int NODEREF(i_ptr[10]); + int NODEREF(i_ptr2[10])[10]; +} + +typedef int NODEREF *(*func5[10])(int); + +// Arguments +void func6(int NODEREF x); // expected-warning{{'noderef' can only be used on an array or pointer type}} +void func7(int NODEREF *x); +void func8() NODEREF; + +void References() { + int x = 2; + int NODEREF &y = x; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *xp = &x; + int NODEREF *&a = xp; // ok (reference to a NODEREF *) + int *NODEREF &b = xp; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +void BlockPointers() { + typedef int NODEREF (^IntBlock)(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +class A { +public: + int member; + int NODEREF *member2; + int NODEREF member3; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; + +void MemberPointer() { + int NODEREF A::*var = &A::member; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +template +class B { + Ty NODEREF *member; + Ty NODEREF member2; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; Index: test/Frontend/noderef.c === --- /dev/null +++ test/Frontend/noderef.c @@ -0,0 +1,154 @@ +// RUN: %clang_cc1 -Wno-unused-value -verify %s + +#define NODEREF __attribute__((noderef)) + +struct S { + int a; + int b; +}; + +struct S2 { + int a[2]; + int NODEREF a2[2]; + int *b; + int NODEREF *b2; + struct S *s; + struct S NODEREF *s2; +}; + +int NODEREF *func(int NODEREF *arg) { // expected-note{{arg declared here}} + int y = *arg; // expected-warning{{dereferencing arg; was declared with a 'noderef' type}} + return arg; +} + +void func2(int x) {} + +int test() { + int NODEREF *p; // expected-note 31 {{p declared here}} + int *p2; + + int x = *p; // expected-warning{{dereferencing p; was declared with a 'noderef' type}} + x = *((int NODEREF *)p2); // expected-warning{{dereferencing expression marked as 'noderef'}} + +
[PATCH] D50278: [Sema] Fix for crash on conditional operation with address_space pointer
leonardchan added inline comments. Comment at: include/clang/Basic/DiagnosticSemaKinds.td:6943 +def err_typecheck_incompatible_conditional_pointer_operands : Error< + "unable to find common type between %0 and %1 for conditional operation">; ebevhan wrote: > This error is very similar to the one in my first comment, `conditional > operator with the second and third operands of type > ('__attribute__((address_space(1))) char *' and > '__attribute__((address_space(2))) char *') which are pointers to > non-overlapping address spaces`. It would normally be emitted at 6472, but > won't be since OpenCL isn't enabled. Done. Removing the check for OpenCL throws this instead of the warning. Comment at: lib/Sema/SemaExpr.cpp:6522 +bool HasDifferingLAddrSpace = LAddrSpace != ResultAddrSpace; +bool HasDifferingRAddrSpace = RAddrSpace != ResultAddrSpace; + rjmccall wrote: > I was going to tell you to use the predicate > `Qualifiers::isAddressSpaceSupersetOf` here, but then I was looking at the > uses of that, and I think the real fix is to just go into the implementation > of `checkConditionalPointerCompatibility` and make the compatibility logic > not OpenCL-specific. The fast-path should just be whether the address spaces > are different. > > And it looks like this function has a bug where it always uses > `LangAS::Default` outside of OpenCL even if the pointers are in the same > address space. I'm not sure how the `LangAS::Default`, but removing all checks for OpenCL does the trick and prints an existing error relating to different address_spaces on conditional operands to replace the warning. Only 2 tests needed the change from the expected warning to expected error without having to change any OpenCL tests. I also think the address_space comparison is already done with the `lhQual.isAddressSpaceSupersetOf` and `rhQual.isAddressSpaceSupersetOf`. Comment at: test/Sema/conditional-expr.c:78 + // expected-error@-1{{converting '__attribute__((address_space(2))) int *' to type 'void *' changes address space of pointer}} + // expected-error@-2{{converting '__attribute__((address_space(3))) int *' to type 'void *' changes address space of pointer}} ebevhan wrote: > rjmccall wrote: > > leonardchan wrote: > > > rjmccall wrote: > > > > Also, these diagnostics seem wrong. Where is `void *` coming from? > > > When dumping the AST this is what the resulting type is for the > > > conditional expression already is if the operands are 2 pointers with > > > different address spaces. > > > > > > According to this comment, the reason seems to be because this is what > > > GCC does: > > > > > > ``` > > > 6512 // In this situation, we assume void* type. No especially good > > > 6513 // reason, but this is what gcc does, and we do have to pick > > > 6514 // to get a consistent AST. > > > ``` > > That makes sense in general, but in this case it's not a great diagnostic; > > we should just emit an error when trying to pick a common type. > Is it possible that you are getting `void *` because we aren't running the > qualifier removal at 6495? I don't think I've ever seen spurious `void *`'s > show up in our downstream diagnostics. So the `void *` is what get's dumped for me using the latest upstream version of clang and is the result of the `ConditionalOperator`. An AST dump of ``` 3 unsigned long test0 = 5; 4 int __attribute__((address_space(2))) *adr2; 5 int __attribute__((address_space(3))) *adr3; 6 test0 ? adr2 : adr3; ``` for me returns ``` `-ConditionalOperator 0xbdbcab0 'void *' |-ImplicitCastExpr 0xbdbc690 'unsigned long' | `-DeclRefExpr 0xbdbc618 'unsigned long' lvalue Var 0xbdbc348 'test0' 'unsigned long' |-ImplicitCastExpr 0xbdbc790 'void *' | `-ImplicitCastExpr 0xbdbc6a8 '__attribute__((address_space(2))) int *' | `-DeclRefExpr 0xbdbc640 '__attribute__((address_space(2))) int *' lvalue Var 0xbdbc490 'adr2' '__attribute__((address_space(2))) int *' `-ImplicitCastExpr 0xbdbc7a8 'void *' `-ImplicitCastExpr 0xbdbc6c0 '__attribute__((address_space(3))) int *' `-DeclRefExpr 0xbdbc668 '__attribute__((address_space(3))) int *' lvalue Var 0xbdbc5a0 'adr3' '__attribute__((address_space(3))) int *' ``` Repository: rC Clang https://reviews.llvm.org/D50278 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50278: [Sema] Fix for crash on conditional operation with address_space pointer
leonardchan updated this revision to Diff 159559. leonardchan marked an inline comment as done. leonardchan added a comment. - Removed checks for OpenCL in `checkConditionalPointerCompatibility`. This allows for the error `err_typecheck_op_on_nonoverlapping_address_space_pointers` to be dumped on getting pointers with different address spaces instead of the warning `ext_typecheck_cond_incompatible_pointers`. Repository: rC Clang https://reviews.llvm.org/D50278 Files: lib/Sema/SemaExpr.cpp test/Sema/address_spaces.c test/Sema/conditional-expr.c Index: test/Sema/conditional-expr.c === --- test/Sema/conditional-expr.c +++ test/Sema/conditional-expr.c @@ -73,10 +73,10 @@ int __attribute__((address_space(2))) *adr2; int __attribute__((address_space(3))) *adr3; - test0 ? adr2 : adr3; // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + test0 ? adr2 : adr3; // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(2))) int *' and '__attribute__((address_space(3))) int *') which are pointers to non-overlapping address spaces}} // Make sure address-space mask ends up in the result type - (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(2))) int *' and 'int *') which are pointers to non-overlapping address spaces}} } int Postgresql() { Index: test/Sema/address_spaces.c === --- test/Sema/address_spaces.c +++ test/Sema/address_spaces.c @@ -71,5 +71,5 @@ // Clang extension doesn't forbid operations on pointers to different address spaces. char* cmp(_AS1 char *x, _AS2 char *y) { - return x < y ? x : y; // expected-warning {{pointer type mismatch ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *')}} + return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *') which are pointers to non-overlapping address spaces}} } Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -6461,20 +6461,18 @@ LangAS ResultAddrSpace = LangAS::Default; LangAS LAddrSpace = lhQual.getAddressSpace(); LangAS RAddrSpace = rhQual.getAddressSpace(); - if (S.getLangOpts().OpenCL) { -// OpenCL v1.1 s6.5 - Conversion between pointers to distinct address -// spaces is disallowed. -if (lhQual.isAddressSpaceSupersetOf(rhQual)) - ResultAddrSpace = LAddrSpace; -else if (rhQual.isAddressSpaceSupersetOf(lhQual)) - ResultAddrSpace = RAddrSpace; -else { - S.Diag(Loc, - diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) - << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); - return QualType(); -} + + // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address + // spaces is disallowed. + if (lhQual.isAddressSpaceSupersetOf(rhQual)) +ResultAddrSpace = LAddrSpace; + else if (rhQual.isAddressSpaceSupersetOf(lhQual)) +ResultAddrSpace = RAddrSpace; + else { +S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) +<< LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() +<< RHS.get()->getSourceRange(); +return QualType(); } unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers(); @@ -6492,16 +6490,12 @@ // Thus for conditional operator we merge CVR and address space unqualified // pointees and if there is a composite type we return a pointer to it with // merged qualifiers. - if (S.getLangOpts().OpenCL) { -LHSCastKind = LAddrSpace == ResultAddrSpace - ? CK_BitCast - : CK_AddressSpaceConversion; -RHSCastKind = RAddrSpace == ResultAddrSpace - ? CK_BitCast - : CK_AddressSpaceConversion; -lhQual.removeAddressSpace(); -rhQual.removeAddressSpace(); - } + LHSCastKind = + LAddrSpace == ResultAddrSpace ? CK_BitCast : CK_AddressSpaceConversion; + RHSCastKind = + RAddrSpace == ResultAddrSpace ? CK_BitCast : CK_AddressSpaceConversion; + lhQual.removeAddressSpace(); + rhQual.removeAddressSpace(); lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); @@ -6517,6 +6511,7 @@ S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpac
[PATCH] D50278: [Sema] Fix for crash on conditional operation with address_space pointer
This revision was automatically updated to reflect the committed changes. Closed by commit rC339167: [Sema] Fix for crash on conditional operation with address_space pointer (authored by leonardchan, committed by ). Repository: rL LLVM https://reviews.llvm.org/D50278 Files: lib/Sema/SemaExpr.cpp test/Sema/address_spaces.c test/Sema/conditional-expr.c Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -6460,20 +6460,18 @@ LangAS ResultAddrSpace = LangAS::Default; LangAS LAddrSpace = lhQual.getAddressSpace(); LangAS RAddrSpace = rhQual.getAddressSpace(); - if (S.getLangOpts().OpenCL) { -// OpenCL v1.1 s6.5 - Conversion between pointers to distinct address -// spaces is disallowed. -if (lhQual.isAddressSpaceSupersetOf(rhQual)) - ResultAddrSpace = LAddrSpace; -else if (rhQual.isAddressSpaceSupersetOf(lhQual)) - ResultAddrSpace = RAddrSpace; -else { - S.Diag(Loc, - diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) - << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); - return QualType(); -} + + // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address + // spaces is disallowed. + if (lhQual.isAddressSpaceSupersetOf(rhQual)) +ResultAddrSpace = LAddrSpace; + else if (rhQual.isAddressSpaceSupersetOf(lhQual)) +ResultAddrSpace = RAddrSpace; + else { +S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) +<< LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() +<< RHS.get()->getSourceRange(); +return QualType(); } unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers(); @@ -6491,16 +6489,12 @@ // Thus for conditional operator we merge CVR and address space unqualified // pointees and if there is a composite type we return a pointer to it with // merged qualifiers. - if (S.getLangOpts().OpenCL) { -LHSCastKind = LAddrSpace == ResultAddrSpace - ? CK_BitCast - : CK_AddressSpaceConversion; -RHSCastKind = RAddrSpace == ResultAddrSpace - ? CK_BitCast - : CK_AddressSpaceConversion; -lhQual.removeAddressSpace(); -rhQual.removeAddressSpace(); - } + LHSCastKind = + LAddrSpace == ResultAddrSpace ? CK_BitCast : CK_AddressSpaceConversion; + RHSCastKind = + RAddrSpace == ResultAddrSpace ? CK_BitCast : CK_AddressSpaceConversion; + lhQual.removeAddressSpace(); + rhQual.removeAddressSpace(); lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); @@ -6516,6 +6510,7 @@ S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace)); LHS = S.ImpCastExprToType(LHS.get(), incompatTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), incompatTy, RHSCastKind); + // FIXME: For OpenCL the warning emission and cast to void* leaves a room // for casts between types with incompatible address space qualifiers. // For the following code the compiler produces casts between global and @@ -6526,6 +6521,7 @@ S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return incompatTy; } Index: test/Sema/address_spaces.c === --- test/Sema/address_spaces.c +++ test/Sema/address_spaces.c @@ -71,5 +71,5 @@ // Clang extension doesn't forbid operations on pointers to different address spaces. char* cmp(_AS1 char *x, _AS2 char *y) { - return x < y ? x : y; // expected-warning {{pointer type mismatch ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *')}} + return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *') which are pointers to non-overlapping address spaces}} } Index: test/Sema/conditional-expr.c === --- test/Sema/conditional-expr.c +++ test/Sema/conditional-expr.c @@ -73,10 +73,10 @@ int __attribute__((address_space(2))) *adr2; int __attribute__((address_space(3))) *adr3; - test0 ? adr2 : adr3; // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + test0 ? adr2 : adr3; // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(2))) int *' and '__attribute__((address_space(3))) int *') which are pointers to non-overlapping address spaces}} // Make sure address-space mask ends up in the result type - (test0 ? (test0 ?
[PATCH] D50278: [Sema] Fix for crash on conditional operation with address_space pointer
This revision was automatically updated to reflect the committed changes. Closed by commit rL339167: [Sema] Fix for crash on conditional operation with address_space pointer (authored by leonardchan, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D50278?vs=159559&id=159576#toc Repository: rL LLVM https://reviews.llvm.org/D50278 Files: cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/Sema/address_spaces.c cfe/trunk/test/Sema/conditional-expr.c Index: cfe/trunk/test/Sema/conditional-expr.c === --- cfe/trunk/test/Sema/conditional-expr.c +++ cfe/trunk/test/Sema/conditional-expr.c @@ -73,10 +73,10 @@ int __attribute__((address_space(2))) *adr2; int __attribute__((address_space(3))) *adr3; - test0 ? adr2 : adr3; // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + test0 ? adr2 : adr3; // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(2))) int *' and '__attribute__((address_space(3))) int *') which are pointers to non-overlapping address spaces}} // Make sure address-space mask ends up in the result type - (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(2))) int *' and 'int *') which are pointers to non-overlapping address spaces}} } int Postgresql() { Index: cfe/trunk/test/Sema/address_spaces.c === --- cfe/trunk/test/Sema/address_spaces.c +++ cfe/trunk/test/Sema/address_spaces.c @@ -71,5 +71,5 @@ // Clang extension doesn't forbid operations on pointers to different address spaces. char* cmp(_AS1 char *x, _AS2 char *y) { - return x < y ? x : y; // expected-warning {{pointer type mismatch ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *')}} + return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *') which are pointers to non-overlapping address spaces}} } Index: cfe/trunk/lib/Sema/SemaExpr.cpp === --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -6460,20 +6460,18 @@ LangAS ResultAddrSpace = LangAS::Default; LangAS LAddrSpace = lhQual.getAddressSpace(); LangAS RAddrSpace = rhQual.getAddressSpace(); - if (S.getLangOpts().OpenCL) { -// OpenCL v1.1 s6.5 - Conversion between pointers to distinct address -// spaces is disallowed. -if (lhQual.isAddressSpaceSupersetOf(rhQual)) - ResultAddrSpace = LAddrSpace; -else if (rhQual.isAddressSpaceSupersetOf(lhQual)) - ResultAddrSpace = RAddrSpace; -else { - S.Diag(Loc, - diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) - << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); - return QualType(); -} + + // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address + // spaces is disallowed. + if (lhQual.isAddressSpaceSupersetOf(rhQual)) +ResultAddrSpace = LAddrSpace; + else if (rhQual.isAddressSpaceSupersetOf(lhQual)) +ResultAddrSpace = RAddrSpace; + else { +S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) +<< LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() +<< RHS.get()->getSourceRange(); +return QualType(); } unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers(); @@ -6491,16 +6489,12 @@ // Thus for conditional operator we merge CVR and address space unqualified // pointees and if there is a composite type we return a pointer to it with // merged qualifiers. - if (S.getLangOpts().OpenCL) { -LHSCastKind = LAddrSpace == ResultAddrSpace - ? CK_BitCast - : CK_AddressSpaceConversion; -RHSCastKind = RAddrSpace == ResultAddrSpace - ? CK_BitCast - : CK_AddressSpaceConversion; -lhQual.removeAddressSpace(); -rhQual.removeAddressSpace(); - } + LHSCastKind = + LAddrSpace == ResultAddrSpace ? CK_BitCast : CK_AddressSpaceConversion; + RHSCastKind = + RAddrSpace == ResultAddrSpace ? CK_BitCast : CK_AddressSpaceConversion; + lhQual.removeAddressSpace(); + rhQual.removeAddressSpace(); lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); @@ -6516,6 +6510,7 @@ S.Context.getAddrSpa
[PATCH] D48909: [clang-doc] Update BitcodeReader to use llvm::Error
leonardchan added a comment. Should there be any tests associated with these changes? Comment at: clang-tools-extra/clang-doc/BitcodeReader.cpp:308 - llvm::errs() << "Invalid type for info.\n"; - exit(1); } Probably not important or it's just me being picky/dumb, but is this exit the intended behavior of this program when reaching this function? If so, should the exit also be expected even when using llvm::Error? This also applies to the other times exit() is called in these add functions. Comment at: clang-tools-extra/clang-doc/BitcodeReader.cpp:311 -template <> void addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) { I->Members.emplace_back(std::move(T)); Is it necessary to change the return value to llvm::Error for what were originally void functions? https://reviews.llvm.org/D48909 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D43424: [clang-doc] Implement a (simple) Markdown generator
leonardchan accepted this revision. leonardchan added inline comments. This revision is now accepted and ready to land. Comment at: clang-tools-extra/clang-doc/MDGenerator.cpp:79 + +void writeHeader(const Twine &Text, int Num, raw_ostream &OS) { + OS << std::string(Num, '#') + " " + Text << "\n"; nit: make `Num` unsigned since the `std::string` fill ctor takes an unsigned value https://reviews.llvm.org/D43424 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan added a comment. @rsmith any more feedback on this current version? If it still looks incorrect to use the record this way, I don't mind simplifying it to work on lvalue to rvalue conversions without checking for a leading address space operation. Repository: rC Clang https://reviews.llvm.org/D49511 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan created this revision. leonardchan added reviewers: ebevhan, phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch is a part of https://reviews.llvm.org/D48456 in an attempt to split them up. This contains the code for casting between fixed point types and other fixed point types. The method for converting between fixed point types is based off the convert() method in APFixedPoint. Repository: rC Clang https://reviews.llvm.org/D50616 Files: include/clang/AST/OperationKinds.def include/clang/AST/Type.h lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/AST/Type.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/Sema.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_conversions.c Index: test/Frontend/fixed_point_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_conversions.c @@ -0,0 +1,326 @@ +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - | FileCheck %s -check-prefix=DEFAULT +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s -check-prefix=SAME + +void TestFixedPointCastSameType() { + _Accum a = 2.5k; + _Accum a2 = a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 + + a2 = (_Accum)a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 +} + +void TestFixedPointCastDown() { + long _Accum la = 2.5lk; + _Accum a = la; + // DEFAULT: [[LACCUM:%[0-9]+]] = load i64, i64* %la, align 8 + // DEFAULT-NEXT: [[ACCUM_AS_I64:%[0-9]+]] = ashr i64 [[LACCUM]], 16 + // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = trunc i64 [[ACCUM_AS_I64]] to i32 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4 + + a = (_Accum)la; + // DEFAULT: [[LACCUM:%[0-9]+]] = load i64, i64* %la, align 8 + // DEFAULT-NEXT: [[ACCUM_AS_I64:%[0-9]+]] = ashr i64 [[LACCUM]], 16 + // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = trunc i64 [[ACCUM_AS_I64]] to i32 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4 + + short _Accum sa = a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: [[SACCUM_AS_I32:%[0-9]+]] = ashr i32 [[ACCUM]], 8 + // DEFAULT-NEXT: [[SACCUM:%[0-9]+]] = trunc i32 [[SACCUM_AS_I32]] to i16 + // DEFAULT-NEXT: store i16 [[SACCUM]], i16* %sa, align 2 + + sa = (short _Accum)a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: [[SACCUM_AS_I32:%[0-9]+]] = ashr i32 [[ACCUM]], 8 + // DEFAULT-NEXT: [[SACCUM:%[0-9]+]] = trunc i32 [[SACCUM_AS_I32]] to i16 + // DEFAULT-NEXT: store i16 [[SACCUM]], i16* %sa, align 2 +} + +void TestFixedPointCastUp() { + short _Accum sa = 2.5hk; + _Accum a = sa; + // DEFAULT: [[SACCUM:%[0-9]+]] = load i16, i16* %sa, align 2 + // DEFAULT-NEXT: [[SACCUM_BUFF:%[0-9]+]] = sext i16 [[SACCUM]] to i24 + // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = shl i24 [[SACCUM_BUFF]], 8 + // DEFAULT-NEXT: [[ACCUM_EXT:%[0-9]+]] = sext i24 [[ACCUM]] to i32 + // DEFAULT-NEXT: store i32 [[ACCUM_EXT]], i32* %a, align 4 + + long _Accum la = a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: [[ACCUM_BUFF:%[0-9]+]] = sext i32 [[ACCUM]] to i48 + // DEFAULT-NEXT: [[LACCUM:%[0-9]+]] = shl i48 [[ACCUM_BUFF]], 16 + // DEFAULT-NEXT: [[LACCUM_EXT:%[0-9]+]] = sext i48 [[LACCUM]] to i64 + // DEFAULT-NEXT: store i64 [[LACCUM_EXT]], i64* %la, align 8 + + a = (_Accum)sa; + // DEFAULT: [[SACCUM:%[0-9]+]] = load i16, i16* %sa, align 2 + // DEFAULT-NEXT: [[SACCUM_BUFF:%[0-9]+]] = sext i16 [[SACCUM]] to i24 + // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = shl i24 [[SACCUM_BUFF]], 8 + // DEFAULT-NEXT: [[ACCUM_EXT:%[0-9]+]] = sext i24 [[ACCUM]] to i32 + // DEFAULT-NEXT: store i32 [[ACCUM_EXT]], i32* %a, align 4 + + la = (long _Accum)a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: [[ACCUM_BUFF:%[0-9]+]] = sext i32 [[ACCUM]] to i48 + // DEFAULT-NEXT: [[LACCUM:%[0-9]+]] = shl i48 [[ACCUM_BUFF]], 16 + // DEFAULT-NEXT: [[LACCUM_EXT:%[0-9]+]] = sext i48 [[LACCUM]] to i64 + // DEFAULT-NEXT: store i64 [[LACCUM_EXT]], i64* %la, align 8 +} + +void TestFixedPointCastSignedness() { + _Accum a = 2.5k; + unsigned _Accum ua = a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: [[ACCUM_EXT:%[0-9]+]] = sext i32 [[ACCUM]] to i33 + // DEFAULT-NEXT: [[UACCUM:%[0-9]+]] = shl i33 [[ACCUM_EXT]], 1 + // DEFAULT-NEXT: [[ACCUM_TRUNC:%[0-9]+]] = trunc i33 [[UACCUM]] to i32 + // DEFAULT-NEXT: store i32 [[ACCUM_TRUNC]], i32* %ua, align 4 + // SAME: TestFixedPointCastSignedness + // SAME: [[ACCUM:%[0-9]+]] = load i32, i32* %
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan updated this revision to Diff 160403. leonardchan marked an inline comment as done. leonardchan added a comment. - Checks for sugared types and expressions wrapped in parenthesis Repository: rC Clang https://reviews.llvm.org/D49511 Files: include/clang/AST/Type.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/Type.cpp lib/AST/TypePrinter.cpp lib/Parse/ParseExpr.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprMember.cpp lib/Sema/SemaType.cpp test/Frontend/noderef.c test/Frontend/noderef_on_non_pointers.cpp test/Frontend/noderef_on_non_pointers.m Index: test/Frontend/noderef_on_non_pointers.m === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.m @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +#define NODEREF __attribute__((noderef)) + +@interface NSObject ++ (id)new; +@end + +void func() { + id NODEREF obj = [NSObject new]; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} Index: test/Frontend/noderef_on_non_pointers.cpp === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -fblocks -verify %s + +/** + * Test 'noderef' attribute against other pointer-like types. + */ + +#define NODEREF __attribute__((noderef)) + +void Normal() { + int NODEREF i;// expected-warning{{'noderef' can only be used on an array or pointer type}} + int NODEREF *i_ptr; // ok + int NODEREF **i_ptr2; // ok + int *NODEREF i_ptr3; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *NODEREF *i_ptr4; // ok + + auto NODEREF *auto_i_ptr = i_ptr; + auto NODEREF auto_i = i; // expected-warning{{'noderef' can only be used on an array or pointer type}} + + struct { +int x; +int y; + } NODEREF *s; + + int __attribute__((noderef(10))) * no_args; // expected-error{{'noderef' attribute takes no arguments}} +} + +const int NODEREF *const_i_ptr; +static int NODEREF *static_i_ptr; + +void ParenTypes() { + int NODEREF(*i_ptr);// ok (same as `int NODEREF *`) + int NODEREF *(*i_ptr2); // ok (same as `int NODEREF **`) +} + +// Function declarations +int NODEREF func(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +int NODEREF *func2(); // ok (returning pointer) + +typedef int NODEREF (*func3)(int); // expected-warning{{'noderef' can only be used on an array or pointer type}} +typedef int NODEREF *(*func4)(int); + +void Arrays() { + int NODEREF i_arr[10]; // ok + int NODEREF i_arr2[10][10]; // ok + int NODEREF *i_arr3[10];// ok + int NODEREF i_arr4[] = {1, 2}; +} + +void ParenArrays() { + int NODEREF(i_ptr[10]); + int NODEREF(i_ptr2[10])[10]; +} + +typedef int NODEREF *(*func5[10])(int); + +// Arguments +void func6(int NODEREF x); // expected-warning{{'noderef' can only be used on an array or pointer type}} +void func7(int NODEREF *x); +void func8() NODEREF; + +void References() { + int x = 2; + int NODEREF &y = x; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *xp = &x; + int NODEREF *&a = xp; // ok (reference to a NODEREF *) + int *NODEREF &b = xp; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +void BlockPointers() { + typedef int NODEREF (^IntBlock)(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +class A { +public: + int member; + int NODEREF *member2; + int NODEREF member3; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; + +void MemberPointer() { + int NODEREF A::*var = &A::member; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +template +class B { + Ty NODEREF *member; + Ty NODEREF member2; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; Index: test/Frontend/noderef.c === --- /dev/null +++ test/Frontend/noderef.c @@ -0,0 +1,188 @@ +// RUN: %clang_cc1 -Wno-unused-value -verify %s + +#define NODEREF __attribute__((noderef)) + +struct S { + int a; + int b; +}; + +struct S2 { + int a[2]; + int NODEREF a2[2]; + int *b; + int NODEREF *b2; + struct S *s; + struct S NODEREF *s2; +}; + +int NODEREF *func(int NODEREF *arg) { // expected-note{{arg declared here}} + int y = *arg; // expected-warning{{dereferencing arg; was declared with a 'noderef' type}} + return arg; +} + +void func2(int x) {} + +int test() { + int NODEREF *p; // expected-note 37 {{p declared here}} + int *p2; + + int x = *p; // expected-warning{{dereferencing p; was declared with a 'noderef' type}} + x = *((int NODEREF *)p2); // expected-warning{{dereferencing expression marked
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan added a comment. @rsmith Comment at: lib/Sema/SemaExpr.cpp:14249 + +if (Sema::TypeHasNoDeref(Inner)) + DeclRef = E; aaron.ballman wrote: > The sugar was stripped off at the pointer level, but not at the pointee > level. e.g., > ``` > typedef int (bobble); > typedef bobble * (frobble); > typedef frobble * yobble; > > yobble gobble; > ``` > I think you can handle this within `TypeHasNoDeref()` and that should fix up > all the callers. So `TypeHasNoDeref()` checks for the attribute on the base type already and is called after the pointer is stripped off. Attempting to desugar via `getDesugaredType()` here also removes the `address_space` attribute from the type I'm checking. Do you know another method that essentially "expands" the typedefs without stripping the qualifiers? Otherwise I think I do need do the desugaring at the pointer level. Alternatively I could also change this method such that it accepts pointers instead of pointees since it appears I already call `getDesugaredType()` for almost every pointer who's pointee I'm passing to `TypeHasNoDeref()`. Also I tested with your example and the warning still seems to be thrown appropriately. Repository: rC Clang https://reviews.llvm.org/D49511 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan updated this revision to Diff 160451. leonardchan marked 3 inline comments as done. leonardchan added a comment. - Remove sugar from pointee types Repository: rC Clang https://reviews.llvm.org/D49511 Files: include/clang/AST/Type.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/Type.cpp lib/AST/TypePrinter.cpp lib/Parse/ParseExpr.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprMember.cpp lib/Sema/SemaType.cpp test/Frontend/noderef.c test/Frontend/noderef_on_non_pointers.cpp test/Frontend/noderef_on_non_pointers.m Index: test/Frontend/noderef_on_non_pointers.m === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.m @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +#define NODEREF __attribute__((noderef)) + +@interface NSObject ++ (id)new; +@end + +void func() { + id NODEREF obj = [NSObject new]; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} Index: test/Frontend/noderef_on_non_pointers.cpp === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -fblocks -verify %s + +/** + * Test 'noderef' attribute against other pointer-like types. + */ + +#define NODEREF __attribute__((noderef)) + +void Normal() { + int NODEREF i;// expected-warning{{'noderef' can only be used on an array or pointer type}} + int NODEREF *i_ptr; // ok + int NODEREF **i_ptr2; // ok + int *NODEREF i_ptr3; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *NODEREF *i_ptr4; // ok + + auto NODEREF *auto_i_ptr = i_ptr; + auto NODEREF auto_i = i; // expected-warning{{'noderef' can only be used on an array or pointer type}} + + struct { +int x; +int y; + } NODEREF *s; + + int __attribute__((noderef(10))) * no_args; // expected-error{{'noderef' attribute takes no arguments}} +} + +const int NODEREF *const_i_ptr; +static int NODEREF *static_i_ptr; + +void ParenTypes() { + int NODEREF(*i_ptr);// ok (same as `int NODEREF *`) + int NODEREF *(*i_ptr2); // ok (same as `int NODEREF **`) +} + +// Function declarations +int NODEREF func(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +int NODEREF *func2(); // ok (returning pointer) + +typedef int NODEREF (*func3)(int); // expected-warning{{'noderef' can only be used on an array or pointer type}} +typedef int NODEREF *(*func4)(int); + +void Arrays() { + int NODEREF i_arr[10]; // ok + int NODEREF i_arr2[10][10]; // ok + int NODEREF *i_arr3[10];// ok + int NODEREF i_arr4[] = {1, 2}; +} + +void ParenArrays() { + int NODEREF(i_ptr[10]); + int NODEREF(i_ptr2[10])[10]; +} + +typedef int NODEREF *(*func5[10])(int); + +// Arguments +void func6(int NODEREF x); // expected-warning{{'noderef' can only be used on an array or pointer type}} +void func7(int NODEREF *x); +void func8() NODEREF; + +void References() { + int x = 2; + int NODEREF &y = x; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *xp = &x; + int NODEREF *&a = xp; // ok (reference to a NODEREF *) + int *NODEREF &b = xp; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +void BlockPointers() { + typedef int NODEREF (^IntBlock)(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +class A { +public: + int member; + int NODEREF *member2; + int NODEREF member3; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; + +void MemberPointer() { + int NODEREF A::*var = &A::member; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +template +class B { + Ty NODEREF *member; + Ty NODEREF member2; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; Index: test/Frontend/noderef.c === --- /dev/null +++ test/Frontend/noderef.c @@ -0,0 +1,205 @@ +// RUN: %clang_cc1 -Wno-unused-value -verify %s + +#define NODEREF __attribute__((noderef)) + +struct S { + int a; + int b; +}; + +struct S2 { + int a[2]; + int NODEREF a2[2]; + int *b; + int NODEREF *b2; + struct S *s; + struct S NODEREF *s2; +}; + +int NODEREF *func(int NODEREF *arg) { // expected-note{{arg declared here}} + int y = *arg; // expected-warning{{dereferencing arg; was declared with a 'noderef' type}} + return arg; +} + +void func2(int x) {} + +int test() { + int NODEREF *p; // expected-note 37 {{p declared here}} + int *p2; + + int x = *p; // expected-warning{{dereferencing p; was declared with a 'noderef' type}} + x = *((int NODEREF *)p2); // expected-warning{{dereferencing expression marked as 'noderef'}} + + int NODEREF
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan added inline comments. Comment at: lib/Sema/SemaExpr.cpp:14249 + +if (Sema::TypeHasNoDeref(Inner)) + DeclRef = E; aaron.ballman wrote: > leonardchan wrote: > > aaron.ballman wrote: > > > The sugar was stripped off at the pointer level, but not at the pointee > > > level. e.g., > > > ``` > > > typedef int (bobble); > > > typedef bobble * (frobble); > > > typedef frobble * yobble; > > > > > > yobble gobble; > > > ``` > > > I think you can handle this within `TypeHasNoDeref()` and that should fix > > > up all the callers. > > So `TypeHasNoDeref()` checks for the attribute on the base type already and > > is called after the pointer is stripped off. Attempting to desugar via > > `getDesugaredType()` here also removes the `address_space` attribute from > > the type I'm checking. > > > > Do you know another method that essentially "expands" the typedefs without > > stripping the qualifiers? Otherwise I think I do need do the desugaring at > > the pointer level. Alternatively I could also change this method such that > > it accepts pointers instead of pointees since it appears I already call > > `getDesugaredType()` for almost every pointer who's pointee I'm passing to > > `TypeHasNoDeref()`. > > > > Also I tested with your example and the warning still seems to be thrown > > appropriately. > I think you have to do the desugaring manually in a loop with > `getSingleStepDesugaredType()` so that you don't strip off attributed type > information along with the rest of the type sugar. > > > Also I tested with your example and the warning still seems to be thrown > > appropriately. > > The example may depend on where you put the attribute (inside the parens vs > outside the parens, for instance); it was an off-the-cuff example, so it may > need some tweaking. Done. Also added different variations of your example to the tests. Repository: rC Clang https://reviews.llvm.org/D49511 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan updated this revision to Diff 160884. leonardchan marked 3 inline comments as done. leonardchan added a comment. - Added check for if we should check for saturation when converting to a saturated fixed point type. - Replaced `llvm_unreachable()`s with temporary diagnostic to be eventually replaced when the conversions get implemented. Repository: rC Clang https://reviews.llvm.org/D50616 Files: include/clang/AST/OperationKinds.def include/clang/AST/Type.h include/clang/Basic/DiagnosticCommonKinds.td lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/AST/Type.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/Sema.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_conversions.c test/Frontend/fixed_point_unknown_conversions.c Index: test/Frontend/fixed_point_unknown_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_unknown_conversions.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -verify -ffixed-point %s + +void func() { + _Bool b; + char c; + int i; + float f; + double d; + double _Complex dc; + int _Complex ic; + struct S { +int i; + } s; + enum E { +A + } e; + int *ptr; + typedef int int_t; + int_t i2; + + _Accum accum; + _Fract fract = accum; // ok + _Accum *accum_ptr; + + accum = b; // expected-error{{conversion between fixed point and '_Bool' is not yet supported}} + accum = i; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + accum = i; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + accum = f; // expected-error{{conversion between fixed point and 'float' is not yet supported}} + accum = d; // expected-error{{conversion between fixed point and 'double' is not yet supported}} + accum = dc; // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}} + accum = ic; // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}} + accum = s; // expected-error{{assigning to '_Accum' from incompatible type 'struct S'}} + accum = e; // expected-error{{conversion between fixed point and 'enum E' is not yet supported}} + accum = ptr; // expected-error{{assigning to '_Accum' from incompatible type 'int *'}} + accum_ptr = ptr; // expected-warning{{incompatible pointer types assigning to '_Accum *' from 'int *'}} + accum = i2; // expected-error{{conversion between fixed point and 'int_t' (aka 'int') is not yet supported}} + + b = accum; // expected-error{{conversion between fixed point and '_Bool' is not yet supported}} + c = accum; // expected-error{{conversion between fixed point and 'char' is not yet supported}} + i = accum; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + f = accum; // expected-error{{conversion between fixed point and 'float' is not yet supported}} + d = accum; // expected-error{{conversion between fixed point and 'double' is not yet supported}} + dc = accum; // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}} + ic = accum; // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}} + s = accum; // expected-error{{assigning to 'struct S' from incompatible type '_Accum'}} + e = accum; // expected-error{{conversion between fixed point and 'enum E' is not yet supported}} + ptr = accum; // expected-error{{assigning to 'int *' from incompatible type '_Accum'}} + ptr = accum_ptr; // expected-warning{{incompatible pointer types assigning to 'int *' from '_Accum *'}} + i2 = accum; // expected-error{{conversion between fixed point and 'int' is not yet supported}} +} Index: test/Frontend/fixed_point_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_conversions.c @@ -0,0 +1,326 @@ +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - | FileCheck %s -check-prefix=DEFAULT +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s -check-prefix=SAME + +void TestFixedPointCastSameType() { + _Accum a = 2.5k; + _Accum a2 = a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 + + a2 = (_Accum)a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 +} + +void TestFixedPointCastDown() { + long _Accum la = 2.5lk; + _Accum a = la; + // DEFAULT: [[LACCUM:%[0-9]+]] = load i64, i64* %la, align 8 + // DEFAULT-NEXT: [[ACCUM_AS_I64:%[0-9]
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan added inline comments. Comment at: lib/CodeGen/CGExprScalar.cpp:1016 + if (DstScale > SrcScale) { +// Need to allocate space before shifting left +ResultWidth = SrcWidth + DstScale - SrcScale; rjmccall wrote: > In IR, this isn't really "allocating" space. My bad. Poor comment wording. Comment at: lib/CodeGen/CGExprScalar.cpp:1034 + if (DstFPSema.isSaturated() && + (CGF.getContext().getCorrespondingSaturatedType(SrcTy) != DstTy)) { +auto Mask = APInt::getBitsSetFrom( rjmccall wrote: > Why is this condition based on the formal types exactly matching rather than > something about the FP semantics being different? Formal types can > correspond to the same format, right? > > We need to check for saturation if we're either (1) decreasing the magnitude > of the highest usable bit or (2) going signed->unsigned, (2) we're going > signed->unsigned, or (3) we're going unsigned->signed without increasing the > number of integral bits. And I'd expect the checks we have to do in each > case to be different. For simplicity, I more or less copied the logic from `APFixedPoint::convert()` which performs a saturation check that covers all of these cases if the destination semantics were saturated. Added another condition that checks if we need to perform saturation checks. I think your (1) and (3) might be the same thing since I think we only really need to check if the magnitude decreases or if going from signed -> unsigned. I think though that the IR emission would be the same since both cases will require checking for a change in the magnitude (via the mask). The only difference is that if going from signed->unsigned, the min saturation is zero if the value is negative. Comment at: lib/Sema/SemaExpr.cpp:5889 +case Type::STK_MemberPointer: + llvm_unreachable("Unimplemented conversion from FixedPoint to type"); +} rjmccall wrote: > Is there something I'm missing that actually diagnoses the unimplemented > cases here? There's a lot of code that seems to assume that any two > arithmetic types can be converted to each other, and we do prefer not to > crash the compiler, especially on valid code. The plan was to implement these in other patches. I wasn't sure if `llvm_unreachable()` was ok to use as a placeholder for features that will eventually be implemented. Added diagnostics here for now to be eventually removed once these casts are implemented in later patches. Repository: rC Clang https://reviews.llvm.org/D50616 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan updated this revision to Diff 160892. leonardchan marked 6 inline comments as done. Repository: rC Clang https://reviews.llvm.org/D49511 Files: include/clang/AST/Type.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/Type.cpp lib/AST/TypePrinter.cpp lib/Parse/ParseExpr.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprMember.cpp lib/Sema/SemaType.cpp test/Frontend/noderef.c test/Frontend/noderef_on_non_pointers.cpp test/Frontend/noderef_on_non_pointers.m Index: test/Frontend/noderef_on_non_pointers.m === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.m @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +#define NODEREF __attribute__((noderef)) + +@interface NSObject ++ (id)new; +@end + +void func() { + id NODEREF obj = [NSObject new]; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} Index: test/Frontend/noderef_on_non_pointers.cpp === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -fblocks -verify %s + +/** + * Test 'noderef' attribute against other pointer-like types. + */ + +#define NODEREF __attribute__((noderef)) + +void Normal() { + int NODEREF i;// expected-warning{{'noderef' can only be used on an array or pointer type}} + int NODEREF *i_ptr; // ok + int NODEREF **i_ptr2; // ok + int *NODEREF i_ptr3; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *NODEREF *i_ptr4; // ok + + auto NODEREF *auto_i_ptr = i_ptr; + auto NODEREF auto_i = i; // expected-warning{{'noderef' can only be used on an array or pointer type}} + + struct { +int x; +int y; + } NODEREF *s; + + int __attribute__((noderef(10))) * no_args; // expected-error{{'noderef' attribute takes no arguments}} +} + +const int NODEREF *const_i_ptr; +static int NODEREF *static_i_ptr; + +void ParenTypes() { + int NODEREF(*i_ptr);// ok (same as `int NODEREF *`) + int NODEREF *(*i_ptr2); // ok (same as `int NODEREF **`) +} + +// Function declarations +int NODEREF func(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +int NODEREF *func2(); // ok (returning pointer) + +typedef int NODEREF (*func3)(int); // expected-warning{{'noderef' can only be used on an array or pointer type}} +typedef int NODEREF *(*func4)(int); + +void Arrays() { + int NODEREF i_arr[10]; // ok + int NODEREF i_arr2[10][10]; // ok + int NODEREF *i_arr3[10];// ok + int NODEREF i_arr4[] = {1, 2}; +} + +void ParenArrays() { + int NODEREF(i_ptr[10]); + int NODEREF(i_ptr2[10])[10]; +} + +typedef int NODEREF *(*func5[10])(int); + +// Arguments +void func6(int NODEREF x); // expected-warning{{'noderef' can only be used on an array or pointer type}} +void func7(int NODEREF *x); +void func8() NODEREF; + +void References() { + int x = 2; + int NODEREF &y = x; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *xp = &x; + int NODEREF *&a = xp; // ok (reference to a NODEREF *) + int *NODEREF &b = xp; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +void BlockPointers() { + typedef int NODEREF (^IntBlock)(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +class A { +public: + int member; + int NODEREF *member2; + int NODEREF member3; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; + +void MemberPointer() { + int NODEREF A::*var = &A::member; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +template +class B { + Ty NODEREF *member; + Ty NODEREF member2; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; Index: test/Frontend/noderef.c === --- /dev/null +++ test/Frontend/noderef.c @@ -0,0 +1,205 @@ +// RUN: %clang_cc1 -Wno-unused-value -verify %s + +#define NODEREF __attribute__((noderef)) + +struct S { + int a; + int b; +}; + +struct S2 { + int a[2]; + int NODEREF a2[2]; + int *b; + int NODEREF *b2; + struct S *s; + struct S NODEREF *s2; +}; + +int NODEREF *func(int NODEREF *arg) { // expected-note{{arg declared here}} + int y = *arg; // expected-warning{{dereferencing arg; was declared with a 'noderef' type}} + return arg; +} + +void func2(int x) {} + +int test() { + int NODEREF *p; // expected-note 37 {{p declared here}} + int *p2; + + int x = *p; // expected-warning{{dereferencing p; was declared with a 'noderef' type}} + x = *((int NODEREF *)p2); // expected-warning{{dereferencing expression marked as 'noderef'}} + + int NODEREF **q; + int *NODEREF *q2; // expected-note 4 {{q2 declared here}
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan updated this revision to Diff 160964. leonardchan marked 7 inline comments as done. leonardchan added a comment. - Reworked logic for saturation Repository: rC Clang https://reviews.llvm.org/D50616 Files: include/clang/AST/OperationKinds.def include/clang/AST/Type.h include/clang/Basic/DiagnosticCommonKinds.td lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/AST/Type.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/Sema.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_conversions.c test/Frontend/fixed_point_unknown_conversions.c Index: test/Frontend/fixed_point_unknown_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_unknown_conversions.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -verify -ffixed-point %s + +void func() { + _Bool b; + char c; + int i; + float f; + double d; + double _Complex dc; + int _Complex ic; + struct S { +int i; + } s; + enum E { +A + } e; + int *ptr; + typedef int int_t; + int_t i2; + + _Accum accum; + _Fract fract = accum; // ok + _Accum *accum_ptr; + + accum = b; // expected-error{{conversion between fixed point and '_Bool' is not yet supported}} + accum = i; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + accum = i; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + accum = f; // expected-error{{conversion between fixed point and 'float' is not yet supported}} + accum = d; // expected-error{{conversion between fixed point and 'double' is not yet supported}} + accum = dc; // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}} + accum = ic; // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}} + accum = s; // expected-error{{assigning to '_Accum' from incompatible type 'struct S'}} + accum = e; // expected-error{{conversion between fixed point and 'enum E' is not yet supported}} + accum = ptr; // expected-error{{assigning to '_Accum' from incompatible type 'int *'}} + accum_ptr = ptr; // expected-warning{{incompatible pointer types assigning to '_Accum *' from 'int *'}} + accum = i2; // expected-error{{conversion between fixed point and 'int_t' (aka 'int') is not yet supported}} + + b = accum; // expected-error{{conversion between fixed point and '_Bool' is not yet supported}} + c = accum; // expected-error{{conversion between fixed point and 'char' is not yet supported}} + i = accum; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + f = accum; // expected-error{{conversion between fixed point and 'float' is not yet supported}} + d = accum; // expected-error{{conversion between fixed point and 'double' is not yet supported}} + dc = accum; // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}} + ic = accum; // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}} + s = accum; // expected-error{{assigning to 'struct S' from incompatible type '_Accum'}} + e = accum; // expected-error{{conversion between fixed point and 'enum E' is not yet supported}} + ptr = accum; // expected-error{{assigning to 'int *' from incompatible type '_Accum'}} + ptr = accum_ptr; // expected-warning{{incompatible pointer types assigning to 'int *' from '_Accum *'}} + i2 = accum; // expected-error{{conversion between fixed point and 'int' is not yet supported}} +} Index: test/Frontend/fixed_point_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_conversions.c @@ -0,0 +1,294 @@ +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - | FileCheck %s -check-prefix=DEFAULT +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s -check-prefix=SAME + +void TestFixedPointCastSameType() { + _Accum a = 2.5k; + _Accum a2 = a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 + + a2 = (_Accum)a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 +} + +void TestFixedPointCastDown() { + long _Accum la = 2.5lk; + _Accum a = la; + // DEFAULT: [[LACCUM:%[0-9]+]] = load i64, i64* %la, align 8 + // DEFAULT-NEXT: [[ACCUM_AS_I64:%[0-9]+]] = ashr i64 [[LACCUM]], 16 + // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = trunc i64 [[ACCUM_AS_I64]] to i32 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4 + + a = (_Accum)la; + // DEFAU
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan added inline comments. Comment at: lib/CodeGen/CGExprScalar.cpp:1034 + if (DstFPSema.isSaturated() && + (CGF.getContext().getCorrespondingSaturatedType(SrcTy) != DstTy)) { +auto Mask = APInt::getBitsSetFrom( rjmccall wrote: > leonardchan wrote: > > rjmccall wrote: > > > Why is this condition based on the formal types exactly matching rather > > > than something about the FP semantics being different? Formal types can > > > correspond to the same format, right? > > > > > > We need to check for saturation if we're either (1) decreasing the > > > magnitude of the highest usable bit or (2) going signed->unsigned, (2) > > > we're going signed->unsigned, or (3) we're going unsigned->signed without > > > increasing the number of integral bits. And I'd expect the checks we > > > have to do in each case to be different. > > For simplicity, I more or less copied the logic from > > `APFixedPoint::convert()` which performs a saturation check that covers all > > of these cases if the destination semantics were saturated. > > > > Added another condition that checks if we need to perform saturation > > checks. I think your (1) and (3) might be the same thing since I think we > > only really need to check if the magnitude decreases or if going from > > signed -> unsigned. > > > > I think though that the IR emission would be the same since both cases will > > require checking for a change in the magnitude (via the mask). The only > > difference is that if going from signed->unsigned, the min saturation is > > zero if the value is negative. > Wow, sorry for the edit failure in that review comment. You're right, it > should've been just (1) and the first (2). > > Are there no fixed-point formats for which the range doesn't go up to > (almost) 1? I guess there probably aren't. No problem. The smallest range that a fixed point type can cover is the `_Fract` type which covers [-1, 1). Comment at: lib/CodeGen/CGExprScalar.cpp:1044 + +Value *IsNegative = nullptr; +if (Mask != 0) { rjmccall wrote: > I'm sorry, but this code is really impenetrable. The variable names are > non-descriptive, and there are a lot of uncommented dependencies between > values, like how `IsNegative` propagates out, and like how it's checking > without explanation that there's not a magnitude change using whether the > mask ends up being all-zero. Please just assign the two components of > `ShouldCheckSaturation` to reasonably-named local variables and then use > those to guide the code-generation here. > > Also, the code being generated here is pretty weird. I'm not sure the mask > is helping; it might both produce better code and be easier to understand if > you just broke it down into cases, like this: > > ``` > if a magnitude check is required { > auto Max = maximum value of dest type; > auto TooHigh = IsSigned ? Builder.CreateICmpSGT(Result, Max) : > Builder.CreateICmpUGT(Result, Max); > Result = Builder.CreateSelect(TooHigh, Max, Result); > } > > if signed -> unsigned { > auto Zero = zero value of dest type; > Result = Builder.CreateSelect(Builder.CreateICmpSLT(Result, Zero), Zero, > Result); > } else if (IsSigned) { > auto Min = minimum value of dest type; > Result = Builder.CreateSelect(Builder.CreateICmpSLT(Result, Min), Min, > Result); > } > ``` My bad. I guess it seemed intuitive at first but can see how it's difficult to read. This is the full logic and reasoning for the mask: https://reviews.llvm.org/D48661?id=153426#inline-427647 But to summarize, it's essentially for checking if the bits above the MSB changed which would indicate saturation needs to occur. - `Mask` is for getting the bits above the integral bits in the resulting type (for signed types, this also captures the sign bit) - `Masked` is the bits above the highest integral bit in the resulting type - `Masked == Mask` indicates that all the bits above the highest integral bit were ones (the value is negative) and none of them changed (no change in magnitude) - `Mask == 0` indicates that all the bits above the highest integral bit were zeros (the value is non-negative) and none of them changed (no change in magnitude) - `Masked == Mask || Mask == 0` therefore indicates no change in magnitude - `!(Masked == Mask || Mask == 0)` indicates a change in magnitude and we should saturate (but to save an extra instruction, this was emitted as `Masked != Mask && Mask != 0` - If we saturate, `Mask` also happens to be the min value we saturate to for signed types and `~Mask` is also the max value we saturate to. The reason for the `IsNegative` laid out like that is to prevent from emitting an extra instruction for checking a negative value. Repository: rC Clang https://reviews.llvm.org/D50616 ___ cfe-commits mailing list cfe-commits@lists.llvm.org
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan updated this revision to Diff 161087. leonardchan marked 6 inline comments as done. leonardchan added a comment. - Added separate case for conversions to a non-saturated type Repository: rC Clang https://reviews.llvm.org/D50616 Files: include/clang/AST/OperationKinds.def include/clang/AST/Type.h include/clang/Basic/DiagnosticCommonKinds.td lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/AST/Type.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/Sema.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_conversions.c test/Frontend/fixed_point_unknown_conversions.c Index: test/Frontend/fixed_point_unknown_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_unknown_conversions.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -verify -ffixed-point %s + +void func() { + _Bool b; + char c; + int i; + float f; + double d; + double _Complex dc; + int _Complex ic; + struct S { +int i; + } s; + enum E { +A + } e; + int *ptr; + typedef int int_t; + int_t i2; + + _Accum accum; + _Fract fract = accum; // ok + _Accum *accum_ptr; + + accum = b; // expected-error{{conversion between fixed point and '_Bool' is not yet supported}} + accum = i; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + accum = i; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + accum = f; // expected-error{{conversion between fixed point and 'float' is not yet supported}} + accum = d; // expected-error{{conversion between fixed point and 'double' is not yet supported}} + accum = dc; // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}} + accum = ic; // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}} + accum = s; // expected-error{{assigning to '_Accum' from incompatible type 'struct S'}} + accum = e; // expected-error{{conversion between fixed point and 'enum E' is not yet supported}} + accum = ptr; // expected-error{{assigning to '_Accum' from incompatible type 'int *'}} + accum_ptr = ptr; // expected-warning{{incompatible pointer types assigning to '_Accum *' from 'int *'}} + accum = i2; // expected-error{{conversion between fixed point and 'int_t' (aka 'int') is not yet supported}} + + b = accum; // expected-error{{conversion between fixed point and '_Bool' is not yet supported}} + c = accum; // expected-error{{conversion between fixed point and 'char' is not yet supported}} + i = accum; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + f = accum; // expected-error{{conversion between fixed point and 'float' is not yet supported}} + d = accum; // expected-error{{conversion between fixed point and 'double' is not yet supported}} + dc = accum; // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}} + ic = accum; // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}} + s = accum; // expected-error{{assigning to 'struct S' from incompatible type '_Accum'}} + e = accum; // expected-error{{conversion between fixed point and 'enum E' is not yet supported}} + ptr = accum; // expected-error{{assigning to 'int *' from incompatible type '_Accum'}} + ptr = accum_ptr; // expected-warning{{incompatible pointer types assigning to 'int *' from '_Accum *'}} + i2 = accum; // expected-error{{conversion between fixed point and 'int' is not yet supported}} +} Index: test/Frontend/fixed_point_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_conversions.c @@ -0,0 +1,283 @@ +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - | FileCheck %s -check-prefix=DEFAULT +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s -check-prefix=SAME + +void TestFixedPointCastSameType() { + _Accum a = 2.5k; + _Accum a2 = a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 + + a2 = (_Accum)a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 +} + +void TestFixedPointCastDown() { + long _Accum la = 2.5lk; + _Accum a = la; + // DEFAULT: [[LACCUM:%[0-9]+]] = load i64, i64* %la, align 8 + // DEFAULT-NEXT: [[ACCUM_AS_I64:%[0-9]+]] = ashr i64 [[LACCUM]], 16 + // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = trunc i64 [[ACCUM_AS_I64]] to i32 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4 +
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan added inline comments. Comment at: lib/CodeGen/CGExprScalar.cpp:331 + SourceLocation Loc); + /// Emit a conversion from the specified complex type to the specified ebevhan wrote: > What's the plan for the other conversions (int<->fix, float<->fix)? Functions > for those as well? > > What about `EmitScalarConversion`? If it cannot handle conversions of > fixed-point values it should probably be made to assert, since it will likely > mess up. Ideally, my plan was to have separate functions for each cast since it seems the logic for each of them is unique, other than saturation which may be abstracted to its own function and be used by the others. I wasn't sure if I should also place the logic for these casts in `EmitScalarConversion` since `EmitScalarConversion` seemed pretty large enough and thought it was easier if we instead had separate, self contained functions for each fixed point conversion. But I'm open for hearing ideas on different ways on implementing them. Will add the assertion. Comment at: lib/CodeGen/CGExprScalar.cpp:1052 +} else if (IsSigned && !DstFPSema.isSigned()) { + Value *Zero = + ConstantInt::get(CGF.getLLVMContext(), APInt(ResultWidth, 0)); ebevhan wrote: > `ConstantInt::getNullValue`? I did not know about this method. Thanks! Comment at: lib/Sema/Sema.cpp:537 + case Type::STK_FixedPoint: +llvm_unreachable("Unknown cast from FixedPoint to boolean"); } ebevhan wrote: > Will we want to support this? I imagine we would want `_Bool` conversions since logical negation works on fixed point types and more people would probably assume by default for it to also implicitly be converted to a boolean as opposed to not. I also don't think implementing in a later patch this will be too hard. Repository: rC Clang https://reviews.llvm.org/D50616 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan added a comment. In https://reviews.llvm.org/D50616#1202034, @ebevhan wrote: > I think I've mentioned this before, but I would like to discuss the > possibility of adding a target hook(s) for some of these operations > (conversions, arithmetic when it comes). Precisely matching the emitted > saturation operation is virtually impossible for a target. Sorry I forgot to address this also. Just to make sure I understand this correctly since I haven't used these before: target hooks are essentially for emitting target specific code for some operations right? Does this mean that the `EmitFixedPointConversion` function should be moved to a virtual method under `TargetCodeGenInfo` that can be overridden and this is what get's called instead during conversion? Repository: rC Clang https://reviews.llvm.org/D50616 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan updated this revision to Diff 161298. leonardchan marked 4 inline comments as done. Repository: rC Clang https://reviews.llvm.org/D50616 Files: include/clang/AST/OperationKinds.def include/clang/AST/Type.h include/clang/Basic/DiagnosticCommonKinds.td lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/AST/Type.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/TargetInfo.cpp lib/CodeGen/TargetInfo.h lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/Sema.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_conversions.c test/Frontend/fixed_point_unknown_conversions.c Index: test/Frontend/fixed_point_unknown_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_unknown_conversions.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -verify -ffixed-point %s + +void func() { + _Bool b; + char c; + int i; + float f; + double d; + double _Complex dc; + int _Complex ic; + struct S { +int i; + } s; + enum E { +A + } e; + int *ptr; + typedef int int_t; + int_t i2; + + _Accum accum; + _Fract fract = accum; // ok + _Accum *accum_ptr; + + accum = b; // expected-error{{conversion between fixed point and '_Bool' is not yet supported}} + accum = i; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + accum = i; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + accum = f; // expected-error{{conversion between fixed point and 'float' is not yet supported}} + accum = d; // expected-error{{conversion between fixed point and 'double' is not yet supported}} + accum = dc; // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}} + accum = ic; // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}} + accum = s; // expected-error{{assigning to '_Accum' from incompatible type 'struct S'}} + accum = e; // expected-error{{conversion between fixed point and 'enum E' is not yet supported}} + accum = ptr; // expected-error{{assigning to '_Accum' from incompatible type 'int *'}} + accum_ptr = ptr; // expected-warning{{incompatible pointer types assigning to '_Accum *' from 'int *'}} + accum = i2; // expected-error{{conversion between fixed point and 'int_t' (aka 'int') is not yet supported}} + + b = accum; // expected-error{{conversion between fixed point and '_Bool' is not yet supported}} + c = accum; // expected-error{{conversion between fixed point and 'char' is not yet supported}} + i = accum; // expected-error{{conversion between fixed point and 'int' is not yet supported}} + f = accum; // expected-error{{conversion between fixed point and 'float' is not yet supported}} + d = accum; // expected-error{{conversion between fixed point and 'double' is not yet supported}} + dc = accum; // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}} + ic = accum; // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}} + s = accum; // expected-error{{assigning to 'struct S' from incompatible type '_Accum'}} + e = accum; // expected-error{{conversion between fixed point and 'enum E' is not yet supported}} + ptr = accum; // expected-error{{assigning to 'int *' from incompatible type '_Accum'}} + ptr = accum_ptr; // expected-warning{{incompatible pointer types assigning to 'int *' from '_Accum *'}} + i2 = accum; // expected-error{{conversion between fixed point and 'int' is not yet supported}} +} Index: test/Frontend/fixed_point_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_conversions.c @@ -0,0 +1,283 @@ +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - | FileCheck %s -check-prefix=DEFAULT +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s -check-prefix=SAME + +void TestFixedPointCastSameType() { + _Accum a = 2.5k; + _Accum a2 = a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 + + a2 = (_Accum)a; + // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4 +} + +void TestFixedPointCastDown() { + long _Accum la = 2.5lk; + _Accum a = la; + // DEFAULT: [[LACCUM:%[0-9]+]] = load i64, i64* %la, align 8 + // DEFAULT-NEXT: [[ACCUM_AS_I64:%[0-9]+]] = ashr i64 [[LACCUM]], 16 + // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = trunc i64 [[ACCUM_AS_I64]] to i32 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4 + + a = (_Accum)la; + // DEFAULT:
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan added a comment. In https://reviews.llvm.org/D50616#1203692, @ebevhan wrote: > In https://reviews.llvm.org/D50616#1203446, @leonardchan wrote: > > > Sorry I forgot to address this also. Just to make sure I understand this > > correctly since I haven't used these before: target hooks are essentially > > for emitting target specific code for some operations right? Does this mean > > that the `EmitFixedPointConversion` function should be moved to a virtual > > method under `TargetCodeGenInfo` that can be overridden and this is what > > get's called instead during conversion? > > > Yes, the thought I had was to have a virtual function in TargetCodeGenInfo > that would be called first thing in EmitFixedPointConversion, and if it > returns non-null it uses that value instead. It's a bit unfortunate in this > instance as the only thing that doesn't work for us is the saturation, but > letting you configure *parts* of the emission is a bit too specific. Would it be simpler instead just to have the logic contained in the virtual function for `TargetCodeGenInfo` as opposed to returning `nullptr` since any custom target will end up overriding it anyway and ideally not return `nullptr`? In https://reviews.llvm.org/D50616#1203751, @rjmccall wrote: > In https://reviews.llvm.org/D50616#1203692, @ebevhan wrote: > > > In https://reviews.llvm.org/D50616#1203446, @leonardchan wrote: > > > > > Sorry I forgot to address this also. Just to make sure I understand this > > > correctly since I haven't used these before: target hooks are essentially > > > for emitting target specific code for some operations right? Does this > > > mean that the `EmitFixedPointConversion` function should be moved to a > > > virtual method under `TargetCodeGenInfo` that can be overridden and this > > > is what get's called instead during conversion? > > > > > > Yes, the thought I had was to have a virtual function in TargetCodeGenInfo > > that would be called first thing in EmitFixedPointConversion, and if it > > returns non-null it uses that value instead. It's a bit unfortunate in this > > instance as the only thing that doesn't work for us is the saturation, but > > letting you configure *parts* of the emission is a bit too specific. > > > > In https://reviews.llvm.org/D50616#1203635, @rjmccall wrote: > > > > > If this is more than just a hobby — like if there's a backend that wants > > > to do serious work with matching fixed-point operations to hardware > > > support — we should just add real LLVM IR support for fixed-point types > > > instead of adding a bunch of frontend customization hooks. I don't know > > > what better opportunity we're expecting might come along to justify that, > > > and I don't think it's some incredibly onerous task to add a new leaf to > > > the LLVM type hierarchy. Honestly, LLVM programmers across the board > > > have become far too accustomed to pushing things opaquely through an > > > uncooperative IR with an obscure muddle of intrinsics. > > > > > > In the meantime, we can continue working on this code. Even if there's > > > eventually real IR support for fixed-point types, this code will still be > > > useful; it'll just become the core of some legalization pass in the > > > generic backend. > > > > > > It definitely is; our downstream target requires it. As far as I know > > there's no real use case upstream, which is why it's likely quite hard to > > add any extensions to LLVM proper. Our implementation is done through > > intrinsics rather than an extension of the type system, as fixed-point > > numbers are really just integers under the hood. We've always wanted to > > upstream our fixed-point support (or some reasonable adaptation of it) but > > never gotten the impression that it would be possible since there's no > > upstream user. > > > > A mail I sent to the mailing list a while back has more details on our > > implementation, including what intrinsics we've added: > > http://lists.llvm.org/pipermail/cfe-dev/2018-May/058019.html We also have > > an LLVM pass that converts these intrinsics into pure IR, but it's likely > > that it won't work properly with some parts of this upstream design. > > > > Leonard's original proposal for this work has always been Clang-centric and > > never planned for implementing anything on the LLVM side, so we need to > > make due with what we get, but we would prefer as small a diff from > > upstream as possible. > > > Has anyone actually asked LLVM whether they would accept fixed-point types > into IR? I'm just a frontend guy, but it seems to me that there are > advantages to directly representing these operations in a portable way even > if there are no in-tree targets providing special support for them. And > there are certainly in-tree targets that could provide such support if > someone was motivated to do it. I haven't brought this up to llvm-dev, but the main reason for why we decided to only
[PATCH] D50616: [Fixed Point Arithmetic] FixedPointCast
leonardchan added a comment. I made a post on llvm-dev (http://lists.llvm.org/pipermail/llvm-dev/2018-August/125433.html) to see if other people have opinions on this. In the meantime, do you think I should make a separate patch that moves this into an LLVM intrinsic function? Repository: rC Clang https://reviews.llvm.org/D50616 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan updated this revision to Diff 161785. leonardchan marked 6 inline comments as done and an inline comment as not done. Repository: rC Clang https://reviews.llvm.org/D49511 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/TypePrinter.cpp lib/Parse/ParseExpr.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprMember.cpp lib/Sema/SemaType.cpp test/Frontend/noderef.c test/Frontend/noderef_on_non_pointers.cpp test/Frontend/noderef_on_non_pointers.m test/Frontend/noderef_templates.cpp Index: test/Frontend/noderef_templates.cpp === --- /dev/null +++ test/Frontend/noderef_templates.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify %s + +#define NODEREF __attribute__((noderef)) + +template +int func(T NODEREF *a) { // expected-note 2 {{a declared here}} + return *a + 1; // expected-warning 2 {{dereferencing a; was declared with a 'noderef' type}} +} + +void func() { + float NODEREF *f; + int NODEREF *i; + func(f); // expected-note{{in instantiation of function template specialization 'func' requested here}} + func(i); // expected-note{{in instantiation of function template specialization 'func' requested here}} +} Index: test/Frontend/noderef_on_non_pointers.m === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.m @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +#define NODEREF __attribute__((noderef)) + +@interface NSObject ++ (id)new; +@end + +void func() { + id NODEREF obj = [NSObject new]; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} Index: test/Frontend/noderef_on_non_pointers.cpp === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -fblocks -verify %s + +/** + * Test 'noderef' attribute against other pointer-like types. + */ + +#define NODEREF __attribute__((noderef)) + +void Normal() { + int NODEREF i;// expected-warning{{'noderef' can only be used on an array or pointer type}} + int NODEREF *i_ptr; // ok + int NODEREF **i_ptr2; // ok + int *NODEREF i_ptr3; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *NODEREF *i_ptr4; // ok + + auto NODEREF *auto_i_ptr = i_ptr; + auto NODEREF auto_i = i; // expected-warning{{'noderef' can only be used on an array or pointer type}} + + struct { +int x; +int y; + } NODEREF *s; + + int __attribute__((noderef(10))) * no_args; // expected-error{{'noderef' attribute takes no arguments}} +} + +const int NODEREF *const_i_ptr; +static int NODEREF *static_i_ptr; + +void ParenTypes() { + int NODEREF(*i_ptr);// ok (same as `int NODEREF *`) + int NODEREF *(*i_ptr2); // ok (same as `int NODEREF **`) +} + +// Function declarations +int NODEREF func(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +int NODEREF *func2(); // ok (returning pointer) + +typedef int NODEREF (*func3)(int); // expected-warning{{'noderef' can only be used on an array or pointer type}} +typedef int NODEREF *(*func4)(int); + +void Arrays() { + int NODEREF i_arr[10]; // ok + int NODEREF i_arr2[10][10]; // ok + int NODEREF *i_arr3[10];// ok + int NODEREF i_arr4[] = {1, 2}; +} + +void ParenArrays() { + int NODEREF(i_ptr[10]); + int NODEREF(i_ptr2[10])[10]; +} + +typedef int NODEREF *(*func5[10])(int); + +// Arguments +void func6(int NODEREF x); // expected-warning{{'noderef' can only be used on an array or pointer type}} +void func7(int NODEREF *x); +void func8() NODEREF; + +void References() { + int x = 2; + int NODEREF &y = x; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *xp = &x; + int NODEREF *&a = xp; // ok (reference to a NODEREF *) + int *NODEREF &b = xp; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +void BlockPointers() { + typedef int NODEREF (^IntBlock)(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +class A { +public: + int member; + int NODEREF *member2; + int NODEREF member3; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; + +void MemberPointer() { + int NODEREF A::*var = &A::member; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +template +class B { + Ty NODEREF *member; + Ty NODEREF member2; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; Index: test/Frontend/noderef.c === --- /dev/null +++ test/Frontend/noderef.c @@ -0,0 +1,206 @@ +// RUN: %clang_cc1 -Wno-unused-value -verify %s + +#define NODEREF __attribute__((noderef)) + +struct
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan added inline comments. Comment at: lib/Parse/ParseExpr.cpp:1126 + +Actions.StartCheckingNoDeref(); + rsmith wrote: > This parser-driven start/stop mechanism will not work in C++ templates. > Instead, can you remove the "start" part and check the noderef exprs as part > of popping the ExprEvaluationContextRecord? I'm not sure if I should remove the the start and stop methods because for a regular C program, the Push/PopExprEvaluationContextRecord functions don't seem to be called, and even when they are called in C++, the initial record that exists on the stack isn't popped at all. Since pending noderef expressions are still parsed and added to the last record during template instantiation, doing another check when popping covers all noderef exprs added during instantiation. Comment at: lib/Sema/SemaExpr.cpp:14230-14242 +class DeclRefFinder : public ConstEvaluatedExprVisitor { +public: + typedef ConstEvaluatedExprVisitor Inherited; + + DeclRefFinder(ASTContext &Ctx) : Inherited(Ctx) {} + + void VisitDeclRefExpr(const DeclRefExpr *E) { DeclRef = E; } rsmith wrote: > rsmith wrote: > > I don't see any reason to assume that the `DeclRefExpr` found by this > > visitor will be the one you're interested in (the one the `noderef` > > attribute came from). > > > > How about instead you walk over only expressions that you *know* preserve > > `noderef`, and if you can't find a declaration as the source of the > > `noderef` attribute, produce a differently-worded diagnostic that doesn't > > give a variable name? > This comment is marked done but has not been addressed. My bad. My response to this was adding a check in `StopCheckingNoDerefAndWarn` where we check if the `DeclRefExpr` is `nullptr` and throw the appropriate error if it is found or not. Although I can't come up with an example where this doesn't get the declref we want, since the expressions we pass to this visitor are all our marked noderef expressions (which we check via the attribute on the type). So even if we have a complex expression that has multiple declrefs, all noderef declrefs should be checked by this. Comment at: lib/Sema/SemaExpr.cpp:4291 + const QualType &BaseTy = Base->getType(); + QualType ElemTy; + if (const auto *ArrayTy = dyn_cast(BaseTy)) rsmith wrote: > Did you mean to use ElemTy somewhere below? (I'd guess you intended to check > whether it's marked noderef?) Forgot to remove this. Comment at: lib/Sema/SemaType.cpp:4816 + +if (const auto *AT = dyn_cast(T)) + IsNoDeref = AT->getAttrKind() == AttributedType::attr_noderef; rsmith wrote: > rsmith wrote: > > Move this after the check below (directly setting ExpectNoDerefChunk > > instead), and remove the unnecessary IsNoDeref variable. > This is not correct: there could be multiple attributes at this level. You > could fix this locally either by looping through the attributes on the type > or iterating through the ParsedAttrs on the chunk. But I think my preference > would be to store state indicating that we have an unvalidated noderef > attribute on the TypeProcessingState at the point where you create the > AttributedType, and check and clear that flag here when creating a type chunk. After https://reviews.llvm.org/D50526, it seems that the attribute can also be applied in `ConvertDeclSpecToType`, so I added another check for the attributes there. Repository: rC Clang https://reviews.llvm.org/D49511 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan added a comment. In https://reviews.llvm.org/D49511#1206267, @rsmith wrote: > In https://reviews.llvm.org/D49511#1206265, @rsmith wrote: > > > In https://reviews.llvm.org/D49511#1194716, @leonardchan wrote: > > > > > @rsmith any more feedback on this current version? If it still looks > > > incorrect to use the record this way, I don't mind simplifying it to work > > > on lvalue to rvalue conversions without checking for a leading address > > > space operation. > > > > > > I've been thinking more about cleaner ways to implement this (and in > > particular, approaches that will provide more reasonable semantics in C++ > > -- allowing references to `noderef`, for example). We want to disallow > > operands of type `noderef T` to all operations by default, and only allow > > very specific operations on lvalues of type `noderef T` -- taking the > > address, performing member accesses, lvalue casts. The most natural way to > > get that effect would be to add a new form of placeholder type for a > > "dereferenced noderef" expression, that `CheckPlaceholderExpr` rejects, and > > that we add explicit support for in the contexts where such a construct is > > valid. (This is similar to how we handle overloaded function names and > > bound member function expressions in C++, for example.) (When we reach a > > context that "consumes" a dereferenced noderef expression, we'd need to go > > back and patch up its type, but I think that can be handled in a > > straightforward way.) > > > > I think we should also treat `noderef` more like a type qualifier: as an > > important example, if we have a pointer or reference to `noderef struct X`, > > then member access for a member of type `T` should give an lvalue of type > > `noderef T`. > > > Sorry, I forgot to say: I do not think we need to do this for the initial > version of this functionality. This is mostly about cleanly extending the > functionality to cover more C++ constructs. No problem. After this, I will make another patch that does this. Repository: rC Clang https://reviews.llvm.org/D49511 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan updated this revision to Diff 162126. leonardchan marked 13 inline comments as done. Repository: rC Clang https://reviews.llvm.org/D49511 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/TypePrinter.cpp lib/Parse/ParseExpr.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprMember.cpp lib/Sema/SemaType.cpp test/Frontend/noderef.c test/Frontend/noderef_on_non_pointers.cpp test/Frontend/noderef_on_non_pointers.m test/Frontend/noderef_templates.cpp Index: test/Frontend/noderef_templates.cpp === --- /dev/null +++ test/Frontend/noderef_templates.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify %s + +#define NODEREF __attribute__((noderef)) + +template +int func(T NODEREF *a) { // expected-note 2 {{a declared here}} + return *a + 1; // expected-warning 2 {{dereferencing a; was declared with a 'noderef' type}} +} + +void func() { + float NODEREF *f; + int NODEREF *i; + func(f); // expected-note{{in instantiation of function template specialization 'func' requested here}} + func(i); // expected-note{{in instantiation of function template specialization 'func' requested here}} +} Index: test/Frontend/noderef_on_non_pointers.m === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.m @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +#define NODEREF __attribute__((noderef)) + +@interface NSObject ++ (id)new; +@end + +void func() { + id NODEREF obj = [NSObject new]; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} Index: test/Frontend/noderef_on_non_pointers.cpp === --- /dev/null +++ test/Frontend/noderef_on_non_pointers.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -fblocks -verify %s + +/** + * Test 'noderef' attribute against other pointer-like types. + */ + +#define NODEREF __attribute__((noderef)) + +void Normal() { + int NODEREF i;// expected-warning{{'noderef' can only be used on an array or pointer type}} + int NODEREF *i_ptr; // ok + int NODEREF **i_ptr2; // ok + int *NODEREF i_ptr3; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *NODEREF *i_ptr4; // ok + + auto NODEREF *auto_i_ptr = i_ptr; + auto NODEREF auto_i = i; // expected-warning{{'noderef' can only be used on an array or pointer type}} + + struct { +int x; +int y; + } NODEREF *s; + + int __attribute__((noderef(10))) * no_args; // expected-error{{'noderef' attribute takes no arguments}} +} + +const int NODEREF *const_i_ptr; +static int NODEREF *static_i_ptr; + +void ParenTypes() { + int NODEREF(*i_ptr);// ok (same as `int NODEREF *`) + int NODEREF *(*i_ptr2); // ok (same as `int NODEREF **`) +} + +// Function declarations +int NODEREF func(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +int NODEREF *func2(); // ok (returning pointer) + +typedef int NODEREF (*func3)(int); // expected-warning{{'noderef' can only be used on an array or pointer type}} +typedef int NODEREF *(*func4)(int); + +void Arrays() { + int NODEREF i_arr[10]; // ok + int NODEREF i_arr2[10][10]; // ok + int NODEREF *i_arr3[10];// ok + int NODEREF i_arr4[] = {1, 2}; +} + +void ParenArrays() { + int NODEREF(i_ptr[10]); + int NODEREF(i_ptr2[10])[10]; +} + +typedef int NODEREF *(*func5[10])(int); + +// Arguments +void func6(int NODEREF x); // expected-warning{{'noderef' can only be used on an array or pointer type}} +void func7(int NODEREF *x); +void func8() NODEREF; + +void References() { + int x = 2; + int NODEREF &y = x; // expected-warning{{'noderef' can only be used on an array or pointer type}} + int *xp = &x; + int NODEREF *&a = xp; // ok (reference to a NODEREF *) + int *NODEREF &b = xp; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +void BlockPointers() { + typedef int NODEREF (^IntBlock)(); // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +class A { +public: + int member; + int NODEREF *member2; + int NODEREF member3; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; + +void MemberPointer() { + int NODEREF A::*var = &A::member; // expected-warning{{'noderef' can only be used on an array or pointer type}} +} + +template +class B { + Ty NODEREF *member; + Ty NODEREF member2; // expected-warning{{'noderef' can only be used on an array or pointer type}} +}; Index: test/Frontend/noderef.c === --- /dev/null +++ test/Frontend/noderef.c @@ -0,0 +1,206 @@ +// RUN: %clang_cc1 -Wno-unused-value -verify %s + +#define NODEREF __attribute__((noderef)) + +struct S { + int a; + int b; +}; + +s
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan added inline comments. Comment at: lib/Parse/ParseExpr.cpp:1126 + +Actions.StartCheckingNoDeref(); + rsmith wrote: > leonardchan wrote: > > rsmith wrote: > > > This parser-driven start/stop mechanism will not work in C++ templates. > > > Instead, can you remove the "start" part and check the noderef exprs as > > > part of popping the ExprEvaluationContextRecord? > > I'm not sure if I should remove the the start and stop methods because for > > a regular C program, the Push/PopExprEvaluationContextRecord functions > > don't seem to be called, and even when they are called in C++, the initial > > record that exists on the stack isn't popped at all. > > > > Since pending noderef expressions are still parsed and added to the last > > record during template instantiation, doing another check when popping > > covers all noderef exprs added during instantiation. > `PushExpressionEvaluationContext` / `PopExpressionEvaluationContext` are > called regardless of which language we're parsing. If we're missing > `ExpressionEvaluationContext` records around some expression parsing, we > should fix that. We should never be creating expressions within the initial > `ExpressionEvaluationContext` record (except perhaps during error recovery). > > > Since pending noderef expressions are still parsed and added to the last > > record during template instantiation, doing another check when popping > > covers all noderef exprs added during instantiation. > > That's not how template instantiation works in Clang. We don't re-parse, we > perform a recursive tree transformation that does not involve the parser. So when should a new `ExpressionEvaluationContext` be pushed or popped? For the following code: ``` #define NODEREF __attribute__((noderef)) void func(){ int NODEREF *x; *x; } int main(){ func(); } ``` A new context is pushed then popped in C++ but not for C. From what I can tell based off my observations and looking for where `Push/Pop` get called in code, new ones would get added when we enter a new GNU style statement expression, captured region after a pragma, or different error blocks. Comment at: lib/Sema/SemaExpr.cpp:4289 + + if (TypeHasNoDeref(ResultTy)) { +LastRecord.PossibleDerefs.insert(E); rsmith wrote: > Do you ensure that the `noderef` attribute will be on the innermost level of > the array type? I think you'll need to do so in order to warn on: > > ``` > typedef int A[32]; > typedef A __attribute__((noderef)) *B; > int f(B b) { return (*B)[1]; } > ``` > > (Here, we have a pointer to a noderef annotated array of > non-noderef-annotated int. So I think we will not emit a warning from the > first dereference, because we have a pointer to an array, and we will not > emit a warning from the second dereference in the array indexing, because the > result type does not have the noderef attribute.) H, so normally in order to check what's correct, I usually run these examples through `sparse` since that's the tool that actually checks `noderef` for gcc, but it seems that sparse instead diagnoses a warning on the array indexing instead and nothing for the first dereference. This shouldn't be though since, as you pointed out, the array does not have `noderef` types. For a simple array, ``` int __attribute__((noderef)) x[10]; x[0]; ``` `sparse` diagnoses the appropriate warning for the array index. Personally though, I would chalk this up to an edge case that wasn't thought of before in sparse, since something like this isn't handled on their existing validation tests. Currently, this diagnoses a warning on the first dereference, but I can also understand why it shouldn't warn because accessing `noderef` structs shouldn't warn if the member accessed is an array. The only case though this applies in sparse's tests are with structs and they don't provide a test for dereferencing a pointer to an array. I think the reason for why the struct example still passes is that if the member is an array, none of the actual data in the struct is being accessed. Instead, the value returned is just a pointer to the start of the array within the struct and equivalent to just adding an offset to the struct pointer. I think that no warning should also be thrown for this example if it is guaranteed that array `A` can similarly be found from simple pointer arithmetic on pointer `B`. I don't think it can unless B were an array or struct also, but I could be wrong or overthinking this. Repository: rC Clang https://reviews.llvm.org/D49511 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 145993. leonardchan added a comment. - Restrict usage of fixed point types only to C https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -542,6 +548,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +//CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +//CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +//CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +//CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +//CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +//CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +//CHECK-NEXT: |-VarDecl {{.*}} short_accum 'short _Accum' +//CHECK-NEXT: |-VarDecl {{.*}} accum '_Accum' +//CHECK-NEXT: `-VarDecl {{.*}} long_accum 'long _Accum' Index: lib/Serialization/ASTReader.cpp === --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6816,6 +6816,24 @@ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; +case PREDEF_TYPE_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; +case PREDEF_TYPE_ACCUM_ID: + T = Context.Acc
[PATCH] D46911: Addition of the remaining fixed point types and their saturated equivalents
leonardchan created this revision. leonardchan added a project: clang. This diff includes changes for the remaining _Fract and _Sat fixed point types. signed short _Fract s_short_fract; signed _Fract s_fract; signed long _Fract s_long_fract; unsigned short _Fract u_short_fract; unsigned _Fract u_fract; unsigned long _Fract u_long_fract; // Aliased fixed point types short _Accum short_accum; _Accum accum; long _Accum long_accum; short _Fract short_fract; _Fract fract; long _Fract long_fract; // Saturated fixed point types _Sat signed short _Accum sat_s_short_accum; _Sat signed _Accum sat_s_accum; _Sat signed long _Accum sat_s_long_accum; _Sat unsigned short _Accum sat_u_short_accum; _Sat unsigned _Accum sat_u_accum; _Sat unsigned long _Accum sat_u_long_accum; _Sat signed short _Fract sat_s_short_fract; _Sat signed _Fract sat_s_fract; _Sat signed long _Fract sat_s_long_fract; _Sat unsigned short _Fract sat_u_short_fract; _Sat unsigned _Fract sat_u_fract; _Sat unsigned long _Fract sat_u_long_fract; // Aliased saturated fixed point types _Sat short _Accum sat_short_accum; _Sat _Accum sat_accum; _Sat long _Accum sat_long_accum; _Sat short _Fract sat_short_fract; _Sat _Fract sat_fract; _Sat long _Fract sat_long_fract; This diff only allows for declaration of these fixed point types. Assignment and other operations done on fixed point types according to http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf will be added in future patches. This is a parent of https://reviews.llvm.org/D46084 Repository: rC Clang https://reviews.llvm.org/D46911 Files: include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_errors.cpp Index: test/Frontend/fixed_point_errors.c === --- /dev/null +++ test/Frontend/fixed_point_errors.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} +unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} + +_Sat int i; // expected-error{{'int' cannot be saturated. Only _Fract and _Accum can.}} +_Sat _Sat _Fract fract; // expected-warning{{duplicate '_Sat' declaration specifier}} + +_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat unsigned long long _Accum sat_u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat long long _Fract sat_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +_Sat unsigned long long _Fract sat_u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} Index: test/Frontend/fixed_point.c === --- /dev/null +++ test/Frontend/fixed_point.c @@ -0,0 +1,82 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; +signed short _Fract s_short_fract; +signed _Fract s_fract; +signed long _Fract s_long_fract; +unsigned short _Fract u_short_fract; +unsigned _Fract u_fract; +unsigned long _Fract u_long_fract; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; +short _Fract short_fract; +_Fract fract; +long _Fract long_fract; + +// Saturated fixed point types +_Sat signed short _Accum sat_s_short_accum; +_Sat signed _Accum sat_s_accum; +_Sat signed long _Accum sat_s_long_accum; +_Sat unsigned short _Accum sat_u_short_accum; +_Sat unsigned _Accum sat_u_accum; +_Sat unsigned long _Accum sat_u_long_accum; +_Sat signed short _Fract sat_s_short_fract; +_Sat signed _Fract sat_s_
[PATCH] D46915: Set Fixed Point Precision Bits and Create Fixed Point Literals
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. Herald added a subscriber: mgorny. This diff includes the logic for setting the precision bits for each primary fixed point type when building clang and logic for initializing a fixed point literal. The precision bits are set when building cmake via the flags SACCUM_FBIT ACCUM_FBIT LACCUM_FBIT ... More checks to ensure the bit values used are valid will be added in future patches. Fixed point literals are declared using the suffixes hr: short _Fract uhr: unsigned short _Fract r: _Fract ur: unsigned _Fract lr: long _Fract ulr: unsigned long _Fract hk: short _Accum uhk: unsigned short _Accum k: _Accum uk: unsigned _Accum Errors are also thrown for literal values that exceed the range of the type corresponding to the suffix unsigned short _Accum u_short_accum = 256.0uhk; // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}} This is a parent of https://reviews.llvm.org/D46911 Repository: rC Clang https://reviews.llvm.org/D46915 Files: CMakeLists.txt cmake/modules/InitFixedPointBits.cmake include/clang/AST/Expr.h include/clang/AST/OperationKinds.def include/clang/AST/RecursiveASTVisitor.h include/clang/AST/Type.h include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/FixedPoint.h.in include/clang/Basic/StmtNodes.td include/clang/Lex/LiteralSupport.h lib/AST/ASTContext.cpp lib/AST/ASTDumper.cpp lib/AST/Expr.cpp lib/AST/ExprClassification.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtProfile.cpp lib/AST/Type.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Lex/LiteralSupport.cpp lib/Sema/Sema.cpp lib/Sema/SemaExceptionSpec.cpp lib/Sema/SemaExpr.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_declarations.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_validation.c tools/libclang/CXCursor.cpp Index: tools/libclang/CXCursor.cpp === --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -305,6 +305,10 @@ K = CXCursor_IntegerLiteral; break; + case Stmt::FixedPointLiteralClass: +llvm_unreachable("No cursor for FixedPointLiteralClass"); +break; + case Stmt::FloatingLiteralClass: K = CXCursor_FloatingLiteral; break; Index: test/Frontend/fixed_point_validation.c === --- /dev/null +++ test/Frontend/fixed_point_validation.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli + +// Run simple validation tests + +#define assert(b) if (!(b)) { return 1; } + +int main(){ + short _Accum s_accum; + short _Accum s_accum2 = 2.0hk; + short _Fract s_fract = 0.999hr; + short _Fract s_fract2 = -0.999hr; + + assert(s_accum == 0); + + s_accum = s_accum2; + + assert(s_accum == s_accum2); + assert(s_accum == 2); +} Index: test/Frontend/fixed_point_errors.c === --- test/Frontend/fixed_point_errors.c +++ test/Frontend/fixed_point_errors.c @@ -1,14 +1,23 @@ // RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s -long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} -unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} -long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} -unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} +unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} _Sat int i; // expected-error{{'int' cannot be saturated. Only _Fract and _Accum can.}} _Sat _Sat _Fract fract; // expected-warning{{duplicate '_Sat' declaration specifier}} -_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} _Sat unsigned long long _Accum sat_u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} -_Sat long long _Fract sat_longlong_fract; // expected-error{
[PATCH] D46917: Comparison and Unary Operations for Fixed Point Types
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr. leonardchan added a project: clang. This patch contains logic and tests for different unary and comparison operations on fixed point types, and casting between integers and fixed point types. The operations are `==`, `!=`, `>`, `<`, `>=`, `<=`, `!`, `+`, `-`, `++`, and `--`. `~` is not a supported operation on fixed point types. This is a parent of https://reviews.llvm.org/D46915 Repository: rC Clang https://reviews.llvm.org/D46917 Files: lib/CodeGen/CGExprScalar.cpp lib/Sema/SemaExpr.cpp test/Frontend/fixed_point_declarations.c test/Frontend/fixed_point_validation.c Index: test/Frontend/fixed_point_validation.c === --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -1,19 +1,170 @@ +// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -S -emit-llvm -o - %s | lli +// The first test checks the emitted llvm IR. +// The second test checks the output. +// Both these test require that the default bit widths for the fixed point types +// are used since we check for bit shifted literals that were converted from +// ints and floats. + +// Primary fixed point types +signed short _Accum s_short_accum;// CHECK-DAG: @s_short_accum = common dso_local global i16 0, align 2 +signed _Accum s_accum;// CHECK-DAG: @s_accum =common dso_local global i32 0, align 4 +signed long _Accum s_long_accum; // CHECK-DAG: @s_long_accum = common dso_local global i64 0, align 8 +unsigned short _Accum u_short_accum; // CHECK-DAG: @u_short_accum = common dso_local global i16 0, align 2 +unsigned _Accum u_accum; // CHECK-DAG: @u_accum =common dso_local global i32 0, align 4 +unsigned long _Accum u_long_accum;// CHECK-DAG: @u_long_accum = common dso_local global i64 0, align 8 +signed short _Fract s_short_fract;// CHECK-DAG: @s_short_fract = common dso_local global i16 0, align 2 +signed _Fract s_fract;// CHECK-DAG: @s_fract =common dso_local global i32 0, align 4 +signed long _Fract s_long_fract; // CHECK-DAG: @s_long_fract = common dso_local global i64 0, align 8 +unsigned short _Fract u_short_fract; // CHECK-DAG: @u_short_fract = common dso_local global i16 0, align 2 +unsigned _Fract u_fract; // CHECK-DAG: @u_fract =common dso_local global i32 0, align 4 +unsigned long _Fract u_long_fract;// CHECK-DAG: @u_long_fract = common dso_local global i64 0, align 8 + +// There are 7 bits allocated to the fractional part and 8 +// bits allocated to the integral part of a short _Accum by default. + +signed short _Accum s_short_accum2 = 2.5hk; // CHECK-DAG: @s_short_accum2 = dso_local global i16 320, align 2 +short _Fract short_fract = 0.333hr; // CHECK-DAG: @short_fract = dso_local global i16 42, align 2 + // Run simple validation tests #define assert(b) if (!(b)) { return 1; } int main(){ - short _Accum s_accum; + short _Accum s_accum = 0.0hk; short _Accum s_accum2 = 2.0hk; short _Fract s_fract = 0.999hr; short _Fract s_fract2 = -0.999hr; + const _Fract fract_zero = 0.0r; + // CHECK: %s_accum = alloca i16, align 2 + // CHECK: %s_accum2 = alloca i16, align 2 + // CHECK: %s_fract = alloca i16, align 2 + // CHECK: %s_fract2 = alloca i16, align 2 + // CHECK: %fract_zero = alloca i32, align 4 + // CHECK: store i16 0, i16* %s_accum, align 2 + // CHECK: store i16 256, i16* %s_accum2, align 2 + // CHECK: store i16 127, i16* %s_fract, align 2 + // CHECK: store i16 -127, i16* %s_fract2, align 2 + // CHECK: store i32 0, i32* %fract_zero, align 4 + + / Simple Comparisons ***/ assert(s_accum == 0); + // CHECK: {{.*}} = load i16, i16* %s_accum, align 2 + // CHECK-NEXT: {{.*}} = icmp eq i16 {{.*}}, 0 s_accum = s_accum2; + // CHECK: {{.*}} = load i16, i16* %s_accum2, align 2 + // CHECK-NEXT: store i16 %1, i16* %s_accum, align 2 assert(s_accum == s_accum2); + // CHECK: {{.*}} = load i16, i16* %s_accum, align 2 + // CHECK-NEXT: {{.*}} = load i16, i16* %s_accum2, align 2 + // CHECK-NEXT: {{.*}} = icmp eq i16 {{.*}}, {{.*}} + + assert(s_accum2 == s_accum); + // CHECK: {{.*}} = load i16, i16* %s_accum2, align 2 + // CHECK-NEXT: {{.*}} = load i16, i16* %s_accum, align 2 + // CHECK-NEXT: {{.*}} = icmp eq i16 {{.*}}, {{.*}} + assert(s_accum == 2); + // CHECK: {{.*}} = icmp eq i16 {{.*}}, 256 + + assert(2 == s_accum); + // CHECK: {{.*}} = icmp eq i16 256, {{.*}} + + int x = 2; + assert(s_accum == x); + // CHECK: {{.*}} = load i32, i32* %x, align 4 + // CHECK-NEXT: {{.*}} = trunc i32 {{.*}} to i16 + // CHECK-NEXT: {{.*}} = shl i16 {{.*}}, 7 + // CHECK-NEXT: {{.*}} = icmp eq i16 {{.*}}, {{.*}} + + assert(x == s_accum); + + assert(s_accum
[PATCH] D46925: Remaining Binary Operations on Primary Fixed Point Types
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch implements the remaining arithmetic and logical operations on the primary fixed point types. The operations are `+`, `-`, `*`, `/`, `<<`, and `>>`. // Addition s_accum = 3.0hk; short _Accum s_accum_sum = s_accum + s_accum2; assert(s_accum_sum == 5); assert(s_fract + s_fract2 == 0); // Subtraction short _Accum s_accum_diff = s_accum - s_accum2; assert(s_accum_diff == 1); assert(s_accum2 - s_accum == -1); // Multiplication short _Accum s_accum_mul = s_accum * s_accum2; assert(s_accum_mul == 6); assert(2.0hk * 3.0hk == 6); assert(2.0hk * 3 == 6); assert(2.5hk * 3 == 7.5k); assert(-2.5hk * 3 == -7.5lk); assert(3 * -2.5hk == -7.5hk); assert(-2.5hk * 0 == 0); // Division const short _Accum s_accum3 = 2.5hk; short _Accum s_accum_div = s_accum3 / s_accum2; assert(s_accum_div == 1.25hk); assert(5.0hk / s_accum3 == 2); assert(-5.0hk / s_accum3 == -2); assert(9.9k / 3.3k == 3); assert(9.9hk / 3.3k != 3); // We lose precision when converting between types of different // fractional width. assert(6.75hk / 2.25k == 3); // Unless the fractional part can be evenly represented with // sums of powers of 2. assert(0 / 2.0hk == 0); `%` is not a valod operation on fixed point types. This is the parent of https://reviews.llvm.org/D46917 Repository: rC Clang https://reviews.llvm.org/D46925 Files: include/clang/AST/ASTContext.h include/clang/AST/OperationKinds.def include/clang/AST/Type.h lib/AST/ASTContext.cpp lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/AST/Type.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_validation.c Index: test/Frontend/fixed_point_validation.c === --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -1,5 +1,5 @@ -// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -S -emit-llvm -o - %s | lli +// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s // The first test checks the emitted llvm IR. // The second test checks the output. @@ -74,6 +74,9 @@ assert(2 == s_accum); // CHECK: {{.*}} = icmp eq i16 256, {{.*}} + assert(2 == 2.0hk); + assert(2 != 2.01hk); + int x = 2; assert(s_accum == x); // CHECK: {{.*}} = load i32, i32* %x, align 4 @@ -128,6 +131,46 @@ // numbers. assert(2 == 2.001hk); // This is valid if SACCUM_FBITS == 7 + // Comparisons between fixed-point types + // Signed _Accum to signed _Accum types. + assert(2.5hk == 2.5k); + assert(2.5k == 2.5lk); + assert(-2.5hk == -2.5k); + assert(-2.5k == -2.5lk); + + // Unsigned _Accum to unigned _Accum + assert(2.5uhk == 2.5uk); + assert(2.5uk == 2.5ulk); + + // Signed _Fract to signed _Fract types. + assert(0.333hr != 0.333r); // Loss of precision since different fractional widths + assert(0.333r != 0.333lr); + assert(-0.333hr != -0.333r); + assert(-0.333r != -0.333lr); + + // Unsigned _Fract to unsigned _Fract types. + assert(0.333uhr != 0.333ur); + assert(0.333ur != 0.333ulr); + + // Signed _Accum to signed _Fract + assert(0.333hk == 0.333hr); + assert(0.333k == 0.333r); + assert(0.333lk == 0.333lr); + assert(0.333hk == 0.333r); // Although _Fract has higher precision, it gets casted up to + // short _Accum which (using default precisions) + // has fewer fractional bits. + + // Signed _Accum to unsigned _Fract + assert(0.333hk == 0.333uhr); + assert(0.333k == 0.333ur); + assert(0.333lk == 0.333ulr); + + // Signed _Accum to unsigned _Accum + assert(2.5hk == 2.5uhk); + assert(2.5k == 2.5uk); + assert(2.5lk == 2.5ulk); + + / Unary operations ***/ s_accum = 0.0hk; @@ -167,4 +210,58 @@ assert(+s_fract == s_fract); assert(+s_fract2 == s_fract2); // s_fract2 is negative assert(-s_fract == s_fract2); + + / Binary operations ***/ + + // Addition + s_accum = 3.0hk; + short _Accum s_accum_sum = s_accum + s_accum2; + assert(s_accum_sum == 5); + assert(s_fract + s_fract2 == 0); + + // Subtraction + short _Accum s_accum_diff = s_accum - s_accum2; + assert(s_accum_diff == 1); + assert(s_accum2 - s_accum == -1); + + // Multiplication + short _Accum s_accum_mul = s_accum * s_accum2; + assert(s_accum_mul == 6); + assert(2.0hk * 3.0hk == 6); + assert(2.0hk * 3 == 6); + assert(2.5hk * 3 == 7.5k); + assert(-2.5hk * 3 == -7.5lk); + assert(3 * -2.5hk == -7.5hk); + assert(-2.5hk *
[PATCH] D46926: Conversion between Fixed Point and Floating Point Numbers
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch has the implementation and tests for converting between fixed point and floating point numbers. The conversion process is simply dividing the fixed point value, as an integer, by 2^(# of fractional bits) as a float. This is a parent of https://reviews.llvm.org/D46925 Repository: rC Clang https://reviews.llvm.org/D46926 Files: include/clang/AST/OperationKinds.def include/clang/Basic/DiagnosticSemaKinds.td lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/SemaCast.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_validation.c Index: test/Frontend/fixed_point_validation.c === --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -30,6 +30,7 @@ // Run simple validation tests #define assert(b) if (!(b)) { return 1; } +#define abs(x) x < 0 ? -x : x int main(){ short _Accum s_accum = 0.0hk; @@ -264,4 +265,18 @@ assert(5.0hk >> 2 == 1.25hk); assert(-5.0hk >> 2 == -1.25k); assert(0.0hr >> 2 == 0); + + / Float conversions ***/ + + float f = (float)2.5k; + assert(f > 2.4999 && f < 2.5001); // High precision since the fractional value can be evenly + // represented. + assert((float)2.333hk != 2.333f); + + float base = 2.333f; + float saccum_diff = abs(base - 2.333hk); + float accum_diff = abs(base - 2.333k); + float laccum_diff = abs(base - 2.333lk); + assert(accum_diff < saccum_diff); + assert(laccum_diff < accum_diff); } Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp === --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -321,6 +321,7 @@ const LocationContext *LCtx = Pred->getLocationContext(); switch (CastE->getCastKind()) { + case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_IntegralToFixedPoint: llvm_unreachable("ExprEngine::VisitCast CK_IntegralToFixedPoint"); // TODO case CK_FixedPointCast: llvm_unreachable("CK_FixedPointCast"); // TODO case CK_LValueToRValue: Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -1029,6 +1029,18 @@ return result; } +/// \brief Handle arithmetic conversion from fixed point to floating. Helper function +/// of UsualArithmeticConversions() +static QualType handleFixedPointToFloatConversion(Sema &S, ExprResult &FloatExpr, + ExprResult &FixedPointExpr, + QualType FloatTy, QualType FixedPointTy) { + assert(FloatTy->isFloatingType()); + assert(FixedPointTy->isFixedPointType()); + + FixedPointExpr = S.ImpCastExprToType(FixedPointExpr.get(), FloatTy, CK_FixedPointToFloating); + return FloatTy; +} + /// \brief Handle arithmethic conversion with floating point types. Helper /// function of UsualArithmeticConversions() static QualType handleFloatConversion(Sema &S, ExprResult &LHS, @@ -1057,11 +1069,22 @@ if (LHSType->isHalfType() && !S.getLangOpts().NativeHalfType) LHSType = S.Context.FloatTy; +if (RHSType->isFixedPointType()) { + return handleFixedPointToFloatConversion(S, LHS, RHS, LHSType, + RHSType); +} + return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType, /*convertFloat=*/!IsCompAssign, /*convertInt=*/ true); } assert(RHSFloat); + + if (LHSType->isFixedPointType()) { +return handleFixedPointToFloatConversion(S, RHS, LHS, RHSType, + LHSType); + } + return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType, /*convertInt=*/ true, /*convertFloat=*/!IsCompAssign); @@ -1218,6 +1241,7 @@ CK_IntegralRealToComplex); return ComplexType; } + /// \brief Handle arithmetic conversion from integer to fixed point. Helper function /// of UsualArithmeticConversions() static QualType handleIntToFixedPointConversion(Sema &S, ExprResult &FixedPointExpr, @@ -6028,7 +6052,14 @@ } llvm_unreachable("Should have returned before this"); - case Type::STK_FixedPoint: llvm_unreachable("Sema::PrepareScalarCast from STK_FixedPoint to anything"); // TODO + case Type::STK_F
[PATCH] D46927: Augmented Assignment for Fixed Point Types
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch contains the changes and tests for augmented assignments for primary fixed point types. s_accum = 7.5hk; s_accum2 = 2.0hk; s_accum += s_accum2; assert(s_accum == 9.5hk); s_accum += 2.5k; assert(s_accum == 12); This is a parent of https://reviews.llvm.org/D46926 Repository: rC Clang https://reviews.llvm.org/D46927 Files: include/clang/AST/Type.h lib/AST/Type.cpp lib/CodeGen/CGExprScalar.cpp lib/Sema/SemaExpr.cpp test/Frontend/fixed_point_validation.c Index: test/Frontend/fixed_point_validation.c === --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -279,4 +279,35 @@ float laccum_diff = abs(base - 2.333lk); assert(accum_diff < saccum_diff); assert(laccum_diff < accum_diff); + + / Auxillary assignments ***/ + + s_accum = 7.5hk; + s_accum2 = 2.0hk; + s_accum += s_accum2; + assert(s_accum == 9.5hk); + s_accum += 2.5k; + assert(s_accum == 12); + + s_accum -= s_accum2; + assert(s_accum == 10); + s_accum -= 2.5lk; + assert(s_accum == 7.5k); + + s_accum2 = 3.0k; + s_accum *= s_accum2; + assert(s_accum == 22.5k); + s_accum *= 0.5r; + assert(s_accum == 11.25hk); + + s_accum /= s_accum2; + assert(s_accum == 3.75k); + s_accum /= 0.5hr; + assert(s_accum == 7.5k); + + s_accum <<= 3; + assert(s_accum == 60); + + s_accum >>= 3; + assert(s_accum == 7.5k); } Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -6057,7 +6057,7 @@ default: llvm_unreachable("Unable to convert from fixed point type"); case Type::STK_Integral: llvm_unreachable("Unimplemented scalar cast from fixed point to int"); // TODO case Type::STK_Floating: return CK_FixedPointToFloating; - case Type::STK_FixedPoint: llvm_unreachable("Unimplemented scalar cast from fixed point to fixed point"); // TODO + case Type::STK_FixedPoint: return CK_FixedPointCast; } } Index: lib/CodeGen/CGExprScalar.cpp === --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -308,6 +308,17 @@ Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy, SourceLocation Loc, bool TreatBooleanAsSigned); + /// Emit a conversion between fixed point types by moving the radix point. + /// This does not take into account resizing of the underlying llvm type + /// which should be handled either before or after calling this function. + /// + /// If the type is being scaled up, this method should be called after + /// performing an intcast. If the type is scaled down, this method should be + /// called before performing an intcast. This is necessary such that the + /// shift operations retain as much of the original data as possible before + /// truncation or after extension. + Value *EmitFixedPointRadixShift(Value *Src, QualType SrcTy, QualType DstTy); + /// Emit a conversion from the specified complex type to the specified /// destination type, where the destination type is an LLVM scalar type. Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, @@ -957,6 +968,50 @@ SanitizerHandler::FloatCastOverflow, StaticArgs, OrigSrc); } + +/// Emit a conversion between fixed point types by moving the radix point. +/// This does not take into account resizing of the underlying llvm type +/// which should be handled either before or after calling this function. +/// +/// If the type is being scaled up, this method should be called after +/// performing an intcast. If the type is scaled down, this method should be +/// called before performing an intcast. This is necessary such that the +/// shift operations retain as much of the original data as possible before +/// truncation or after extension. +Value *ScalarExprEmitter::EmitFixedPointRadixShift(Value *Src, QualType SrcTy, + QualType DstTy) { + assert(DstTy->isFixedPointType()); + assert(SrcTy->isFixedPointType()); + + Value* Res = Src; + + // Casting between fixed point types involves separating the integral and + // fractional bits, potentially shifting them, then joining back together. + unsigned dest_fbits = getFixedPointFBits(DstTy); + unsigned src_fbits = getFixedPointFBits(SrcTy); + unsigned dest_ibits = getFixedPointIBits(DstTy); + unsigned src_ibits = getFixedPointIBits(SrcTy); + + // If the number of integral bits is decreasing, trim off any extra bits while + // retaining the sign. + if (dest_ibits < src_ibits) { +Res = Builder.CreateShl(Res, src_ibits - dest_ibits); +Res = Builder.CreateAShr(Res, src_ibits - dest
[PATCH] D46960: [Fixed Point Arithmetic] Predefined Precision Macros
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch contains the addition of the precision macros for integral and fractional bits according to clause 7.18a.3 of http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf. The macros are integer constants and added as predefined macros. // Fractional bits of _Accum types __SACCUM_FBIT__ __ACCUM_FBIT__ __LACCUM_FBIT__ __USACCUM_FBIT__ __UACCUM_FBIT__ __ULACCUM_FBIT__ // Fractional bits of _Fract types __SFRACT_FBIT__ __FRACT_FBIT__ __LFRACT_FBIT__ __USFRACT_FBIT__ __UFRACT_FBIT__ __ULFRACT_FBIT__ // Integral bits of _Accum types __SACCUM_IBIT__ __ACCUM_IBIT__ __LACCUM_IBIT__ __USACCUM_IBIT__ __UACCUM_IBIT__ __ULACCUM_IBIT__ This is a child of https://reviews.llvm.org/D46927 Repository: rC Clang https://reviews.llvm.org/D46960 Files: include/clang/Lex/Preprocessor.h lib/Lex/PPMacroExpansion.cpp test/Frontend/fixed_point_builtin_macros.c Index: test/Frontend/fixed_point_builtin_macros.c === --- /dev/null +++ test/Frontend/fixed_point_builtin_macros.c @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli + +#define assert(b) if (!(b)) { return 1; } + +int main() { + // Test using the recommended values for a typical desktop processor (Annex + // A.3). These are also the default values when building clang. + // Fractional bits of _Accum types + assert(__SACCUM_FBIT__ == 7); + assert(__ACCUM_FBIT__ == 15); + assert(__LACCUM_FBIT__ == 31); + assert(__USACCUM_FBIT__ == 8); + assert(__UACCUM_FBIT__ == 16); + assert(__ULACCUM_FBIT__ == 32); + + // Fractional bits of _Fract types + assert(__SFRACT_FBIT__ == 7); + assert(__FRACT_FBIT__ == 15); + assert(__LFRACT_FBIT__ == 31); + assert(__USFRACT_FBIT__ == 8); + assert(__UFRACT_FBIT__ == 16); + assert(__ULFRACT_FBIT__ == 32); + + // Integral bits of _Accum types + assert(__SACCUM_IBIT__ == 8); + assert(__ACCUM_IBIT__ == 16); + assert(__LACCUM_IBIT__ == 32); + assert(__USACCUM_IBIT__ == 8); + assert(__UACCUM_IBIT__ == 16); + assert(__ULACCUM_IBIT__ == 32); +} Index: lib/Lex/PPMacroExpansion.cpp === --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -14,6 +14,7 @@ #include "clang/Basic/Attributes.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/FixedPoint.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -355,6 +356,31 @@ Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__"); Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__"); + // Fixed point macros (ISO/IEC JTC1 SC22 WG14 N1169) + // Fractional bits of _Accum types + Ident__SACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__SACCUM_FBIT__"); + Ident__ACCUM_FBIT__= RegisterBuiltinMacro(*this, "__ACCUM_FBIT__"); + Ident__LACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__LACCUM_FBIT__"); + Ident__USACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__USACCUM_FBIT__"); + Ident__UACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__UACCUM_FBIT__"); + Ident__ULACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__ULACCUM_FBIT__"); + + // Fractional bits of _Fract types + Ident__SFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__SFRACT_FBIT__"); + Ident__FRACT_FBIT__= RegisterBuiltinMacro(*this, "__FRACT_FBIT__"); + Ident__LFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__LFRACT_FBIT__"); + Ident__USFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__USFRACT_FBIT__"); + Ident__UFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__UFRACT_FBIT__"); + Ident__ULFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__ULFRACT_FBIT__"); + + // Integral bits of _Accum types + Ident__SACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__SACCUM_IBIT__"); + Ident__ACCUM_IBIT__= RegisterBuiltinMacro(*this, "__ACCUM_IBIT__"); + Ident__LACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__LACCUM_IBIT__"); + Ident__USACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__USACCUM_IBIT__"); + Ident__UACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__UACCUM_IBIT__"); + Ident__ULACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__ULACCUM_IBIT__"); + // Microsoft Extensions. if (LangOpts.MicrosoftExt) { Ident__identifier = RegisterBuiltinMacro(*this, "__identifier"); @@ -1696,6 +1722,68 @@ // __LINE__ expands to a simple numeric value. OS << (PLoc.isValid()? PLoc.getLine() : 1); Tok.setKind(tok::numeric_constant); + + // Fixed point macros + // Fractional bits of _Accum types + } else if (II == Ident__SACCUM_FBIT__) { +OS << BUILTIN_SACCUM_FBIT; +Tok.setKind(tok::numeric_constant); + } else if (II == Ident__ACCUM_FBIT__) { +OS << BUILTIN_ACCUM_FBIT; +Tok.setKind(tok::numeric_constant); + } else if (II == Ident_
[PATCH] D46963: [Fixed Point Arithmetic] Test for All Builtin Operations
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch includes a test for checking that all supported builtin operations can be syntactically declared with fixed point types. Tests for asserting the correctness behind each operation will be added in future patches. This is a child of https://reviews.llvm.org/D46960 Repository: rC Clang https://reviews.llvm.org/D46963 Files: lib/AST/ASTContext.cpp lib/CodeGen/CGExprScalar.cpp test/Frontend/fixed_point_all_builtin_operations.c Index: test/Frontend/fixed_point_all_builtin_operations.c === --- /dev/null +++ test/Frontend/fixed_point_all_builtin_operations.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -Werror %s + +// Check that we can use all supported binary and unary operations according to +// clause 4.1.6 in N1169. + +#define ALL_OPERATIONS_FOR_TYPE(TYPE, ID) \ + TYPE unary_add ## ID (TYPE a) { return +a; } \ + TYPE unary_sub ## ID (TYPE a) { return -a; } \ + int logical_not ## ID (TYPE a) { return !a; } \ + TYPE add ## ID (TYPE a, TYPE b) { return a + b; } \ + TYPE sub ## ID (TYPE a, TYPE b) { return a - b; } \ + TYPE mul ## ID (TYPE a, TYPE b) { return a * b; } \ + TYPE div ## ID (TYPE a, TYPE b) { return a / b; } \ + TYPE shl ## ID (TYPE a, int b) { return a << b; } \ + TYPE shr ## ID (TYPE a, int b) { return a >> b; } \ + TYPE augmented_add ## ID (TYPE a, TYPE b) { a += b; return a; } \ + TYPE augmented_sub ## ID (TYPE a, TYPE b) { a -= b; return a; } \ + TYPE augmented_mul ## ID (TYPE a, TYPE b) { a *= b; return a; } \ + TYPE augmented_div ## ID (TYPE a, TYPE b) { a /= b; return a; } \ + TYPE augmented_shl ## ID (TYPE a, int b) { a <<= b; return a; } \ + TYPE augmented_shr ## ID (TYPE a, int b) { a >>= b; return a; } \ + int eq ## ID (TYPE a, TYPE b) { return a == b; } \ + int ne ## ID (TYPE a, TYPE b) { return a != b; } \ + int lt ## ID (TYPE a, TYPE b) { return a < b; } \ + int le ## ID (TYPE a, TYPE b) { return a <= b; } \ + int ge ## ID (TYPE a, TYPE b) { return a >= b; } \ + int gt ## ID (TYPE a, TYPE b) { return a > b; } \ + TYPE pre_inc ## ID (TYPE a) { return ++a; } \ + TYPE pre_dec ## ID (TYPE a) { return --a; } \ + TYPE post_inc ## ID (TYPE a) { return a++; } \ + TYPE post_dec ## ID (TYPE a) { return a--; } \ + TYPE deref_pre_inc ## ID (TYPE *a) { return ++(*a); } \ + TYPE deref_pre_dec ## ID (TYPE *a) { return --(*a); } \ + TYPE deref_post_inc ## ID (TYPE *a) { return (*a)++; } \ + TYPE deref_post_dec ## ID (TYPE *a) { return (*a)--; } + +#define ALL_OPERATIONS(TYPE, ID) \ + ALL_OPERATIONS_FOR_TYPE(TYPE, ID) \ + ALL_OPERATIONS_FOR_TYPE(signed TYPE, Signed ## ID) \ + ALL_OPERATIONS_FOR_TYPE(unsigned TYPE, Unsigned ## ID) \ + ALL_OPERATIONS_FOR_TYPE(_Sat TYPE, Sat ## ID) \ + ALL_OPERATIONS_FOR_TYPE(_Sat signed TYPE, SatSigned ## ID) \ + ALL_OPERATIONS_FOR_TYPE(_Sat unsigned TYPE, SatUnsigned ## ID) + +ALL_OPERATIONS(short _Fract, sf); +ALL_OPERATIONS(_Fract, f); +ALL_OPERATIONS(long _Fract, lf); +ALL_OPERATIONS(short _Accum, sa); +ALL_OPERATIONS(_Accum, a); +ALL_OPERATIONS(long _Accum, la); Index: lib/CodeGen/CGExprScalar.cpp === --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -2204,17 +2204,29 @@ const auto *BT = type->getAs(); switch (BT->getKind()) { default: llvm_unreachable("Not a fixed point type!"); + case BuiltinType::SatShortAccum: case BuiltinType::ShortAccum: fbits = BUILTIN_SACCUM_FBIT; break; + case BuiltinType::SatAccum: case BuiltinType::Accum:fbits = BUILTIN_ACCUM_FBIT; break; + case BuiltinType::SatLongAccum: case BuiltinType::LongAccum:fbits = BUILTIN_LACCUM_FBIT; break; + case BuiltinType::SatUShortAccum: case BuiltinType::UShortAccum: fbits = BUILTIN_USACCUM_FBIT; break; + case BuiltinType::SatUAccum: case BuiltinType::UAccum: fbits = BUILTIN_UACCUM_FBIT; break; + case BuiltinType::SatULongAccum: case BuiltinType::ULongAccum: fbits = BUILTIN_ULACCUM_FBIT; break; + case BuiltinType::SatShortFract: case BuiltinType::ShortFract: fbits = BUILTIN_SFRACT_FBIT; break; + case BuiltinType::SatFract: case BuiltinType::Fract:fbits = BUILTIN_FRACT_FBIT; break; + case BuiltinType::SatLongFract: case BuiltinType::LongFract:fbits = BUILTIN_LFRACT_FBIT; break; + case BuiltinType::SatUShortFract: case BuiltinType::UShortFract: fbits = BUILTIN_USFRACT_FBIT; break; + case BuiltinType::SatUFract: case BuiltinType::UFract: fbits = BUILTIN_UFRACT_FBIT; break; + case BuiltinType::SatULongFract: case BuiltinType::ULongFract: fbits = BUILTIN_ULFRACT_FBIT; break; } llvm::Value *amt = llvm::ConstantInt::get(value->getType(), 1ULL << fbits, Index: lib/AST/A
[PATCH] D46963: [Fixed Point Arithmetic] Test for All Builtin Operations
leonardchan updated this revision to Diff 147131. Repository: rC Clang https://reviews.llvm.org/D46963 Files: lib/AST/ASTContext.cpp lib/CodeGen/CGExprScalar.cpp test/Frontend/fixed_point_all_builtin_operations.c Index: test/Frontend/fixed_point_all_builtin_operations.c === --- /dev/null +++ test/Frontend/fixed_point_all_builtin_operations.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -Werror %s + +// Check that we can use all supported binary and unary operations according to +// clause 4.1.6 in N1169. + +#define ALL_OPERATIONS_FOR_TYPE(TYPE, ID) \ + TYPE unary_add ## ID (TYPE a) { return +a; } \ + TYPE unary_sub ## ID (TYPE a) { return -a; } \ + int logical_not ## ID (TYPE a) { return !a; } \ + TYPE add ## ID (TYPE a, TYPE b) { return a + b; } \ + TYPE sub ## ID (TYPE a, TYPE b) { return a - b; } \ + TYPE mul ## ID (TYPE a, TYPE b) { return a * b; } \ + TYPE div ## ID (TYPE a, TYPE b) { return a / b; } \ + TYPE shl ## ID (TYPE a, int b) { return a << b; } \ + TYPE shr ## ID (TYPE a, int b) { return a >> b; } \ + TYPE augmented_add ## ID (TYPE a, TYPE b) { a += b; return a; } \ + TYPE augmented_sub ## ID (TYPE a, TYPE b) { a -= b; return a; } \ + TYPE augmented_mul ## ID (TYPE a, TYPE b) { a *= b; return a; } \ + TYPE augmented_div ## ID (TYPE a, TYPE b) { a /= b; return a; } \ + TYPE augmented_shl ## ID (TYPE a, int b) { a <<= b; return a; } \ + TYPE augmented_shr ## ID (TYPE a, int b) { a >>= b; return a; } \ + int eq ## ID (TYPE a, TYPE b) { return a == b; } \ + int ne ## ID (TYPE a, TYPE b) { return a != b; } \ + int lt ## ID (TYPE a, TYPE b) { return a < b; } \ + int le ## ID (TYPE a, TYPE b) { return a <= b; } \ + int ge ## ID (TYPE a, TYPE b) { return a >= b; } \ + int gt ## ID (TYPE a, TYPE b) { return a > b; } \ + TYPE pre_inc ## ID (TYPE a) { return ++a; } \ + TYPE pre_dec ## ID (TYPE a) { return --a; } \ + TYPE post_inc ## ID (TYPE a) { return a++; } \ + TYPE post_dec ## ID (TYPE a) { return a--; } \ + TYPE deref_pre_inc ## ID (TYPE *a) { return ++(*a); } \ + TYPE deref_pre_dec ## ID (TYPE *a) { return --(*a); } \ + TYPE deref_post_inc ## ID (TYPE *a) { return (*a)++; } \ + TYPE deref_post_dec ## ID (TYPE *a) { return (*a)--; } + +#define ALL_OPERATIONS(TYPE, ID) \ + ALL_OPERATIONS_FOR_TYPE(TYPE, ID) \ + ALL_OPERATIONS_FOR_TYPE(signed TYPE, Signed ## ID) \ + ALL_OPERATIONS_FOR_TYPE(unsigned TYPE, Unsigned ## ID) \ + ALL_OPERATIONS_FOR_TYPE(_Sat TYPE, Sat ## ID) \ + ALL_OPERATIONS_FOR_TYPE(_Sat signed TYPE, SatSigned ## ID) \ + ALL_OPERATIONS_FOR_TYPE(_Sat unsigned TYPE, SatUnsigned ## ID) + +ALL_OPERATIONS(short _Fract, ShortFract); +ALL_OPERATIONS(_Fract, Fract); +ALL_OPERATIONS(long _Fract, LongFract); +ALL_OPERATIONS(short _Accum, ShortAccum); +ALL_OPERATIONS(_Accum, Accum); +ALL_OPERATIONS(long _Accum, LongAccum); Index: lib/CodeGen/CGExprScalar.cpp === --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -2204,17 +2204,29 @@ const auto *BT = type->getAs(); switch (BT->getKind()) { default: llvm_unreachable("Not a fixed point type!"); + case BuiltinType::SatShortAccum: case BuiltinType::ShortAccum: fbits = BUILTIN_SACCUM_FBIT; break; + case BuiltinType::SatAccum: case BuiltinType::Accum:fbits = BUILTIN_ACCUM_FBIT; break; + case BuiltinType::SatLongAccum: case BuiltinType::LongAccum:fbits = BUILTIN_LACCUM_FBIT; break; + case BuiltinType::SatUShortAccum: case BuiltinType::UShortAccum: fbits = BUILTIN_USACCUM_FBIT; break; + case BuiltinType::SatUAccum: case BuiltinType::UAccum: fbits = BUILTIN_UACCUM_FBIT; break; + case BuiltinType::SatULongAccum: case BuiltinType::ULongAccum: fbits = BUILTIN_ULACCUM_FBIT; break; + case BuiltinType::SatShortFract: case BuiltinType::ShortFract: fbits = BUILTIN_SFRACT_FBIT; break; + case BuiltinType::SatFract: case BuiltinType::Fract:fbits = BUILTIN_FRACT_FBIT; break; + case BuiltinType::SatLongFract: case BuiltinType::LongFract:fbits = BUILTIN_LFRACT_FBIT; break; + case BuiltinType::SatUShortFract: case BuiltinType::UShortFract: fbits = BUILTIN_USFRACT_FBIT; break; + case BuiltinType::SatUFract: case BuiltinType::UFract: fbits = BUILTIN_UFRACT_FBIT; break; + case BuiltinType::SatULongFract: case BuiltinType::ULongFract: fbits = BUILTIN_ULFRACT_FBIT; break; } llvm::Value *amt = llvm::ConstantInt::get(value->getType(), 1ULL << fbits, Index: lib/AST/ASTContext.cpp === --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -1797,6 +1797,10 @@ case BuiltinType::UShortAccum: case BuiltinType::ShortFract: case BuiltinType::UShortFract: +case BuiltinType::SatShortAccum: +case BuiltinTy
[PATCH] D46979: [Fixed Point Arithmetic] Test for Conversion Between Valid Builtin Types
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch contains changes and a test for checking that fixed point types can be converted between all other valid types. Fixed point types can be converted between floating point types, integral types, and other fixed point types. This is a child of https://reviews.llvm.org/D46963 Repository: rC Clang https://reviews.llvm.org/D46979 Files: include/clang/AST/OperationKinds.def lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_all_conversions.c Index: test/Frontend/fixed_point_all_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_all_conversions.c @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -Werror %s + +// Test for conversions between fixed point types and all other valid types. + +// Conversion from one type to another type +#define CONVERT(FROM_TYPE, FROM_ID, TO_TYPE, TO_ID) \ + TO_TYPE FROM_ID ## _to_ ## TO_ID (FROM_TYPE x) { return x; } + +// Conversion between 2 types +#define CONVERT_COMBINATION(TYPE1, ID1, TYPE2, ID2) \ + CONVERT(TYPE1, ID1, TYPE2, ID2) \ + CONVERT(TYPE2, ID2, TYPE1, ID1) + +// Conversion between one type and floating point types +#define CONVERT_BETWEEN_FLOATS(TYPE, ID) \ + CONVERT_COMBINATION(TYPE, ID, float, Float) \ + CONVERT_COMBINATION(TYPE, ID, double, Double) + +// Conversion between one type and an integral type with differant signage +#define CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, INT_TYPE, INT_ID) \ + CONVERT_COMBINATION(TYPE, ID, INT_TYPE, INT_ID) \ + CONVERT_COMBINATION(TYPE, ID, signed INT_TYPE, Signed ## INT_ID) \ + CONVERT_COMBINATION(TYPE, ID, unsigned INT_TYPE, Unsigned ## INT_ID) + +// Conversion between one type and all integral types +#define CONVERT_BETWEEN_INTEGRALS(TYPE, ID) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, char, Char) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, short, Short) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, int, Int) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, long, Long) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, long long, LongLong) + +// Conversion between one type and a fixed point type with different saturation +#define CONVERT_BETWEEN_FIXED_POINT_WITH_SAT(TYPE, ID, FIXED_TYPE, FIXED_ID) \ + CONVERT_COMBINATION(TYPE, ID, FIXED_TYPE, FIXED_ID) \ + CONVERT_COMBINATION(TYPE, ID, _Sat FIXED_TYPE, Sat ## FIXED_ID) + +// Conversion between one type and a fixed point type with different signage +#define CONVERT_BETWEEN_FIXED_POINT_WITH_SIGN(TYPE, ID, FIXED_TYPE, FIXED_ID) \ + CONVERT_BETWEEN_FIXED_POINT_WITH_SAT(TYPE, ID, FIXED_TYPE, FIXED_ID) \ + CONVERT_BETWEEN_FIXED_POINT_WITH_SAT(TYPE, ID, signed FIXED_TYPE, Signed ## FIXED_ID) \ + CONVERT_BETWEEN_FIXED_POINT_WITH_SAT(TYPE, ID, unsigned FIXED_TYPE, Unsigned ## FIXED_ID) + +// Convert between one type and all fixed point types. +// Add "Type" to the end of the ID to avoid multiple definitions of a function +// if the Type is a fixed point type. +#define CONVERT_BETWEEN_FIXED_POINT(TYPE, ID) \ + CONVERT_BETWEEN_FIXED_POINT_WITH_SIGN(TYPE, ID, _Fract, FractType) \ + CONVERT_BETWEEN_FIXED_POINT_WITH_SIGN(TYPE, ID, _Accum, AccumType) + +// Convert between one type and all other types +#define CONVERT_BETWEEN_ALL_TYPES(TYPE, ID) \ + CONVERT_BETWEEN_FLOATS(TYPE, ID) \ + CONVERT_BETWEEN_INTEGRALS(TYPE, ID) \ + CONVERT_BETWEEN_FIXED_POINT(TYPE, ID) + +#define CONVERT_FIXED_POINT_TYPE_WITH_SAT(TYPE, ID) \ + CONVERT_BETWEEN_ALL_TYPES(TYPE, ID) \ + CONVERT_BETWEEN_ALL_TYPES(_Sat TYPE, Sat ## ID) + +#define CONVERT_FIXED_POINT_TYPE(TYPE, ID) \ + CONVERT_FIXED_POINT_TYPE_WITH_SAT(TYPE, ID) \ + CONVERT_FIXED_POINT_TYPE_WITH_SAT(signed TYPE, Signed ## ID) \ + CONVERT_FIXED_POINT_TYPE_WITH_SAT(unsigned TYPE, Unsigned ## ID) + +CONVERT_FIXED_POINT_TYPE(short _Fract, ShortFract); +CONVERT_FIXED_POINT_TYPE(_Fract, Fract); +CONVERT_FIXED_POINT_TYPE(long _Fract, LongFract); + +CONVERT_FIXED_POINT_TYPE(short _Accum, ShortAccum); +CONVERT_FIXED_POINT_TYPE(_Accum, Accum); +CONVERT_FIXED_POINT_TYPE(long _Accum, LongAccum); Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp === --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -321,6 +321,7 @@ const LocationContext *LCtx = Pred->getLocationContext(); switch (CastE->getCastKind()) { + case CK_FloatingToFixedPoint: llvm_unreachable("CK_FloatingToFixedPoint"); case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_IntegralToFixedPoint
[PATCH] D46986: [Fixed Point Arithmetic] Validation Test for Fixed Point Binary Operations and Saturated Addition
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch contains tests for validating the logic behind each builtin operation on fixed point types and tests on addition between saturated _Fract types. - More macros wer added to the FixedPoint.h header on the min and max values for each type which will be required for operations on saturated types. - Updated the logic when converting between fixed point types to take into account saturation. Fixed point type conversions do not fall under the "usual arithmetic conversions" where the resulting type on a binary operation resulting in a fixed point type does not need to be the type of either operands. - Rounded down _Fract literals of 1 (1.0hr, 1.0r, 1.0lr) to the respective maximum values for each _Fract type. This is a child of https://reviews.llvm.org/D46979 Repository: rC Clang https://reviews.llvm.org/D46986 Files: include/clang/AST/Type.h include/clang/Basic/FixedPoint.h.in lib/AST/Type.cpp lib/CodeGen/CGExprScalar.cpp lib/Sema/SemaExpr.cpp test/Frontend/fixed_point_all_builtin_operations.c Index: test/Frontend/fixed_point_all_builtin_operations.c === --- test/Frontend/fixed_point_all_builtin_operations.c +++ test/Frontend/fixed_point_all_builtin_operations.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -Werror %s +// RUN: %clang_cc1 -Werror -S -emit-llvm %s -o - | lli // Check that we can use all supported binary and unary operations according to // clause 4.1.6 in N1169. @@ -48,3 +48,59 @@ ALL_OPERATIONS(short _Accum, ShortAccum); ALL_OPERATIONS(_Accum, Accum); ALL_OPERATIONS(long _Accum, LongAccum); + +#define ASSERT(x) if (!(x)) return 1; + +#define BINARY_OPS_FOR_TYPE(TYPE, ID, SUFFIX) \ + { \ +TYPE a = 0.5 ## SUFFIX; \ +TYPE b = 0.25 ## SUFFIX; \ +ASSERT(add ## ID(a, b) == 0.75 ## SUFFIX); \ +ASSERT(sub ## ID(a, b) == 0.25 ## SUFFIX); \ +ASSERT(mul ## ID(a, b) == 0.125 ## SUFFIX); \ +ASSERT(div ## ID(b, a) == 0.5 ## SUFFIX); \ +ASSERT(shl ## ID(b, 1) == a); \ +ASSERT(shr ## ID(a, 1) == b); \ +ASSERT(lt ## ID(b, a)); \ +ASSERT(le ## ID(b, a)); \ +ASSERT(gt ## ID(a, b)); \ +ASSERT(ge ## ID(a, b)); \ +ASSERT(eq ## ID(a, b) == 0); \ +ASSERT(ne ## ID(a, b)); \ +ASSERT(augmented_add ## ID(a, b) == 0.75 ## SUFFIX); \ +ASSERT(augmented_sub ## ID(a, b) == 0.25 ## SUFFIX); \ +ASSERT(augmented_mul ## ID(a, b) == 0.125 ## SUFFIX); \ +ASSERT(augmented_div ## ID(b, a) == 0.5 ## SUFFIX); \ +ASSERT(augmented_shl ## ID(b, 1) == a); \ +ASSERT(augmented_shr ## ID(a, 1) == b); \ + } + +#define BINARY_OPS(TYPE, ID, SUFFIX) \ + BINARY_OPS_FOR_TYPE(TYPE, ID, SUFFIX); \ + BINARY_OPS_FOR_TYPE(signed TYPE, Signed ## ID, SUFFIX); \ + BINARY_OPS_FOR_TYPE(unsigned TYPE, Unsigned ## ID, u ## SUFFIX); \ + BINARY_OPS_FOR_TYPE(_Sat TYPE, Sat ## ID, SUFFIX); \ + BINARY_OPS_FOR_TYPE(_Sat signed TYPE, SatSigned ## ID, SUFFIX); \ + BINARY_OPS_FOR_TYPE(_Sat unsigned TYPE, SatUnsigned ## ID, u ## SUFFIX); + +#define FRACT_SAT_BINARY_OPS(TYPE, ID, SUFFIX) \ + { \ +TYPE a = 0.7 ## SUFFIX; \ +TYPE b = 0.9 ## SUFFIX; \ +ASSERT(add ## ID(a, b) == 1.0 ## SUFFIX); \ + } + +int main(){ + BINARY_OPS(short _Fract, ShortFract, hr); + BINARY_OPS(_Fract, Fract, r); + BINARY_OPS(long _Fract, LongFract, lr); + BINARY_OPS(short _Accum, ShortAccum, hk); + BINARY_OPS(_Accum, Accum, k); + BINARY_OPS(long _Accum, LongAccum, lk); + + FRACT_SAT_BINARY_OPS(_Sat short _Fract, SatShortFract, hr); + FRACT_SAT_BINARY_OPS(_Sat _Fract, SatFract, r); + FRACT_SAT_BINARY_OPS(_Sat long _Fract, SatLongFract, lr); + + return 0; +} Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -1254,8 +1254,12 @@ return FixedPointTy; } -/// \brief Handle arithmethic conversion with fixed point types. Helper -/// function of UsualArithmeticConversions(). +/// \brief Handle arithmethic conversion with fixed point types. The usual +/// arithmetic conversions do not apply to fixed point type conversions between +/// integers or other fixed point types due to potential loss of precision. +/// For this case of fixed point types, the resulting type in a binary operation +/// does not need to be exactly one of the 2 operand types. +/// Implemented according to Clause 6.3.1.8 of ISO/IEC JTC1 SC22 WG14 N1169. static QualType handleFixedPointConversion(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, @@ -1267,30 +1271,25 @@ bool RHSFixed = RHSType->isFixedPointType(); if (LHSFixed && RHSFixed) { -// Cast up the smaller operand to the bigger +bool LHSSigned = LHSType->isSignedFixedPointType(); +bool RHSSigned = R
[PATCH] D46987: [Fixed Point Arithmetic] Validation Test for Saturated Subtraction on Signed _Fracts
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch includes the logic for subtraction on saturated _Fract types and a test for thm. - Also fixed incorrect minimum value for each _Fract type - Getters for each fixed point min and max value for a given type - Correction when casting from a fixed point to a float. If the fixed point data and sign bits do not take up the whole width of the integer (ie. has padding), we will need to either zero out the padding or extend the sign into the padding if it is negative to ensure the correct floating point value is produced after casting. This is a child of https://reviews.llvm.org/D46986 Repository: rC Clang https://reviews.llvm.org/D46987 Files: include/clang/AST/Type.h include/clang/Basic/FixedPoint.h.in lib/AST/Type.cpp lib/CodeGen/CGExprScalar.cpp test/Frontend/fixed_point_all_builtin_operations.c Index: test/Frontend/fixed_point_all_builtin_operations.c === --- test/Frontend/fixed_point_all_builtin_operations.c +++ test/Frontend/fixed_point_all_builtin_operations.c @@ -88,6 +88,15 @@ TYPE a = 0.7 ## SUFFIX; \ TYPE b = 0.9 ## SUFFIX; \ ASSERT(add ## ID(a, b) == 1.0 ## SUFFIX); \ +a = -0.7 ## SUFFIX; \ +b = -0.9 ## SUFFIX; \ +ASSERT(add ## ID(a, b) == -0.5 ## SUFFIX - 0.5 ## SUFFIX); \ +a = 0.7 ## SUFFIX; \ +b = -0.9 ## SUFFIX; \ +ASSERT(sub ## ID(a, b) == 1.0 ## SUFFIX); \ +a = -0.7 ## SUFFIX; \ +b = 0.9 ## SUFFIX; \ +ASSERT(sub ## ID(a, b) == -0.5 ## SUFFIX - 0.5 ## SUFFIX); \ } int main(){ Index: lib/CodeGen/CGExprScalar.cpp === --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -806,6 +806,11 @@ } Value *VisitAsTypeExpr(AsTypeExpr *CE); Value *VisitAtomicExpr(AtomicExpr *AE); + + // For all fixed point values, we usually do not care about the padding bits, + // but if we convert to another type dependent on the whole value of the + // underlying type, we will need to either zero extend or sign extend. + llvm::Value* FixedPointExtendSignToPadding(const QualType& Ty, llvm::Value* Val); }; } // end anonymous namespace. @@ -1675,6 +1680,41 @@ return true; } +// For all fixed point values, we usually do not care about the padding bits, +// but if we convert to another type dependent on the whole value of the +// underlying type, we will need to either zero extend or sign extend. +llvm::Value* ScalarExprEmitter::FixedPointExtendSignToPadding(const QualType& Ty, + llvm::Value* Val) { + assert(Ty->isFixedPointType()); + + llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ty); + unsigned BitWidth = opTy->getIntegerBitWidth(); + unsigned fbits = getFixedPointFBits(Ty); + unsigned ibits = getFixedPointIBits(Ty); + + if (Ty->isSignedFixedPointType()) { +assert((BitWidth >= fbits + ibits + 1) && + "Cannot fit signed fixed point bits into integral type"); + +unsigned ShiftBits = BitWidth - (fbits + ibits + 1); +if (!ShiftBits) { + return Val; +} + +return Builder.CreateAShr(Builder.CreateShl(Val, ShiftBits), ShiftBits); + } else { +assert((BitWidth >= fbits + ibits) && + "Cannot fit unsigned fixed point bits into integral type"); + +unsigned ShiftBits = BitWidth - (fbits + ibits); +if (!ShiftBits) { + return Val; +} + +return Builder.CreateLShr(Builder.CreateShl(Val, ShiftBits), ShiftBits); + } +} + // VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts // have to handle a more broad range of conversions than explicit casts, as they // handle things like function to ptr-to-function decay etc. @@ -1894,8 +1934,12 @@ assert(DestTy->isFloatingType()); assert(E->getType()->isFixedPointType()); unsigned fbits = getFixedPointFBits(E->getType()); -return Builder.CreateFDiv(EmitScalarConversion(Visit(E), E->getType(), DestTy, CE->getExprLoc()), - llvm::ConstantFP::get(CGF.CGM.FloatTy, (1ULL << fbits) * 1.0)); + +llvm::Value *Val = FixedPointExtendSignToPadding(E->getType(), Visit(E)); +Val = EmitScalarConversion(Val, E->getType(), DestTy, CE->getExprLoc()); + +return Builder.CreateFDiv( +Val, llvm::ConstantFP::get(CGF.CGM.FloatTy, (1ULL << fbits) * 1.0)); } case CK_IntegralCast: @@ -3104,61 +3148,10 @@ assert(op.LHS->getType() == op.RHS->getType()); assert(op.LHS->getType() == opTy); -llvm::Value *SatMaxVal; -llvm::Value *SatMinVal; - -const auto &BT = op.Ty->getAs(); -switch (BT->getKind()) { - default: llvm_unreachable("Unhandled saturated signed fixed point type"); - case BuiltinType::SatShortAccum: - SatMaxVal = llvm::ConstantInt::get(opTy, SACCUM_MAX_AS_INT
[PATCH] D46990: [Fixed Point Arithmetic] Validation Test for Saturated Multiplication
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch contains changes for multiplication on saturated _Fract types. Since we already upcast the underlying integer for the fixed point type, we can do a simple check to see if the resulting value is larger or smaller than the max or min for the fixed point types. This is a child of https://reviews.llvm.org/D46987 Repository: rC Clang https://reviews.llvm.org/D46990 Files: lib/CodeGen/CGExprScalar.cpp test/Frontend/fixed_point_all_builtin_operations.c Index: test/Frontend/fixed_point_all_builtin_operations.c === --- test/Frontend/fixed_point_all_builtin_operations.c +++ test/Frontend/fixed_point_all_builtin_operations.c @@ -97,6 +97,8 @@ a = -0.7 ## SUFFIX; \ b = 0.9 ## SUFFIX; \ ASSERT(sub ## ID(a, b) == -0.5 ## SUFFIX - 0.5 ## SUFFIX); \ +a = -0.5 ## SUFFIX - 0.5 ## SUFFIX; \ +ASSERT(mul ## ID(a, a) == 1.0 ## SUFFIX); \ } int main(){ Index: lib/CodeGen/CGExprScalar.cpp === --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -690,11 +690,84 @@ bufferWidth = 128; } - LHSVal = Builder.CreateIntCast(LHSVal, Builder.getIntNTy(bufferWidth), isSignedResult); - RHSVal = Builder.CreateIntCast(RHSVal, Builder.getIntNTy(bufferWidth), isSignedResult); + llvm::Type *ResultTy = Builder.getIntNTy(bufferWidth); + LHSVal = Builder.CreateIntCast(LHSVal, ResultTy, isSignedResult); + RHSVal = Builder.CreateIntCast(RHSVal, ResultTy, isSignedResult); llvm::Value* MulResult = Builder.CreateMul(LHSVal, RHSVal); MulResult = Builder.CreateAShr(MulResult, getFixedPointFBits(Ops.Ty)); + + // At this point, MulResult has not been truncated yet and still has extra + // assigned bits we can use to check for magnitude overflows. + if (Ops.Ty->isSaturatedFixedPointType()) { +llvm::Value *SatMaxVal = llvm::ConstantInt::get( +ResultTy, getFixedPointMaxVal(Ops.Ty)); +llvm::Value *SatMinVal = llvm::ConstantInt::get( +ResultTy, getFixedPointMinVal(Ops.Ty)); + +unsigned FixedPointBits; +if (Ops.Ty->isSignedFixedPointType()) { + FixedPointBits = getFixedPointIBits(Ops.Ty) + getFixedPointFBits(Ops.Ty) + 1; +} else { + FixedPointBits = getFixedPointIBits(Ops.Ty) + getFixedPointFBits(Ops.Ty); +} +unsigned MSBBitShift = FixedPointBits - 1; + +// Number of data + sign bits used in multiplication result after +// shifting but before truncation. +unsigned UntruncatedBitWidth = FixedPointBits * 2; +unsigned BitMask = (1 << UntruncatedBitWidth) - 1; +llvm::Value *MaskedMulResult = Builder.CreateAnd(MulResult, BitMask); + +if (Ops.Ty->isSignedFixedPointType()) { + if (Ops.Ty->isAccumFixedPointType()) { +llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ops.LHS->getContext()); +llvm::Value *LHSMSB = Builder.CreateIntCast(Builder.CreateLShr(Ops.LHS, MSBBitShift), +Int1Ty, /*isSigned=*/true); +llvm::Value *RHSMSB = Builder.CreateIntCast(Builder.CreateLShr(Ops.RHS, MSBBitShift), +Int1Ty, /*isSigned=*/true); + +// Cap at max if both operand signs were the same and the result is greater than the +// max possible value. +llvm::Value *UseSatMax = Builder.CreateAnd( +Builder.CreateICmpEQ(LHSMSB, RHSMSB), +Builder.CreateICmpUGT(MaskedMulResult, SatMaxVal)); + +// Cap at min if the operands were different, and the unsigned +// respresentation of the result is greater than the maximum possible +// unsigned value that can be represented with the resulting fixed +// point bits. Don't use SatMaxVal here since it represents the max +// for an signed value. +llvm::Value *UseSatMin = Builder.CreateAnd( +Builder.CreateXor(LHSMSB, RHSMSB), +Builder.CreateICmpUGT(MaskedMulResult, llvm::ConstantInt::get(ResultTy, BitMask))); + +MulResult = Builder.CreateSelect( +UseSatMax, SatMaxVal, Builder.CreateSelect(UseSatMin, SatMinVal, MulResult)); + } else { +// The only situation a _Fract overflows is if both are signed and +// equal to -1. Signed multiplication would yield a result of -1 when +// the result should be 1. Instead return the max possible value. +assert(Ops.Ty->isFractFixedPointType()); + +unsigned FractMask = (1ULL << FixedPointBits) - 1; +llvm::Value *MaskedLHSVal = Builder.CreateAnd(LHSVal, FractMask, "Mask
[PATCH] D47016: [Fixed Point Arithmetic] Validation Test for Saturated Division and Comparison Fix
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch includes changes for division on saturated fixed point types. Overflow occurs when the resulting value cannot fit into the number of data bits for the resulting type. For signed division, we cap at the max value of the type when the dividend sign is positive, divisor sign is negative, but the quotient is still positive. Reciprocally, we cap at the min value if the dividend is negative, divisor is positive, and quotient is negative. For unsigned division, overflow occurs if the resulting value exceeds the max possible value that this type can hold. The logic for comparisons between fixed point types was also fixed to account for padding bits. Since the padding bits contains values we do not care about, we mask the fixed point data bits in the underlying integral that we do care about and compare them. This is a child of https://reviews.llvm.org/D46990 Repository: rC Clang https://reviews.llvm.org/D47016 Files: include/clang/AST/Type.h include/clang/Basic/FixedPoint.h.in lib/AST/Type.cpp lib/CodeGen/CGExprScalar.cpp test/Frontend/fixed_point_all_builtin_operations.c test/Frontend/fixed_point_validation.c Index: test/Frontend/fixed_point_validation.c === --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -57,7 +57,7 @@ s_accum = s_accum2; // CHECK: {{.*}} = load i16, i16* %s_accum2, align 2 - // CHECK-NEXT: store i16 %1, i16* %s_accum, align 2 + // CHECK-NEXT: store i16 {{.*}}, i16* %s_accum, align 2 assert(s_accum == s_accum2); // CHECK: {{.*}} = load i16, i16* %s_accum, align 2 @@ -114,9 +114,13 @@ // CHECK: {{.*}} = icmp sgt i16 {{.*}}, {{.*}} assert(s_fract2 < s_fract); - // CHECK: {{.*}} = load i16, i16* %s_fract2, align 2 - // CHECK-NEXT: {{.*}} = load i16, i16* %s_fract, align 2 - // CHECK-NEXT: {{.*}} = icmp slt i16 {{.*}}, {{.*}} + // CHECK: [[VAL:%.+]] = load i16, i16* %s_fract2, align 2 + // CHECK-NEXT: [[VAL2:%.+]] = load i16, i16* %s_fract, align 2 + // CHECK-NEXT: [[SHIFTED_VAL:%.+]] = shl i16 [[VAL]], 8 + // CHECK-NEXT: [[CORRECTED_VAL:%.+]] = ashr i16 [[SHIFTED_VAL]], 8 + // CHECK-NEXT: [[SHIFTED_VAL2:%.+]] = shl i16 [[VAL2]], 8 + // CHECK-NEXT: [[CORRECTED_VAL2:%.+]] = ashr i16 [[SHIFTED_VAL2]], 8 + // CHECK-NEXT: {{.*}} = icmp slt i16 [[CORRECTED_VAL]], [[CORRECTED_VAL2]] assert(s_fract >= s_fract); // CHECK: {{.*}} = icmp sge i16 {{.*}}, {{.*}} Index: test/Frontend/fixed_point_all_builtin_operations.c === --- test/Frontend/fixed_point_all_builtin_operations.c +++ test/Frontend/fixed_point_all_builtin_operations.c @@ -99,6 +99,12 @@ ASSERT(sub ## ID(a, b) == -0.5 ## SUFFIX - 0.5 ## SUFFIX); \ a = -0.5 ## SUFFIX - 0.5 ## SUFFIX; \ ASSERT(mul ## ID(a, a) == 1.0 ## SUFFIX); \ +a = 0.8 ## SUFFIX; \ +b = 0.5 ## SUFFIX; \ +ASSERT(a / b == 1.0 ## SUFFIX); \ +a = -0.8 ## SUFFIX; \ +b = 0.5 ## SUFFIX; \ +ASSERT(a / b == -0.5 ## SUFFIX - 0.5 ## SUFFIX); \ } int main(){ Index: lib/CodeGen/CGExprScalar.cpp === --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -2837,6 +2837,14 @@ assert(LHSTy == RHSTy); bool isSignedResult = LHSTy->isSignedFixedPointType() || RHSTy->isSignedFixedPointType(); +unsigned fbits = getFixedPointFBits(Ops.Ty); +unsigned ibits = getFixedPointIBits(Ops.Ty); +unsigned FixedPointBits; +if (isSignedResult) { + FixedPointBits = fbits + ibits + 1; +} else { + FixedPointBits = fbits + ibits; +} // Round up the bit widths to allocate enough space for calculating the // result. @@ -2848,9 +2856,85 @@ LHSVal = Builder.CreateIntCast(LHSVal, Builder.getIntNTy(bufferWidth), isSignedResult); RHSVal = Builder.CreateIntCast(RHSVal, Builder.getIntNTy(bufferWidth), isSignedResult); -LHSVal = Builder.CreateShl(LHSVal, getFixedPointFBits(LHSTy)); +LHSVal = Builder.CreateShl(LHSVal, fbits); llvm::Value* DivResult = Builder.CreateSDiv(LHSVal, RHSVal); + +if (Ops.Ty->isSaturatedFixedPointType()) { + llvm::Value *SatMaxVal = llvm::ConstantInt::get( + DivResult->getType(), getFixedPointMaxVal(Ops.Ty)); + llvm::Value *SatMinVal = llvm::ConstantInt::get( + DivResult->getType(), getFixedPointMinVal(Ops.Ty)); + + unsigned FixedPointBits; + if (Ops.Ty->isSignedFixedPointType()) { +FixedPointBits = getFixedPointIBits(Ops.Ty) + getFixedPointFBits(Ops.Ty) + 1; + } else { +FixedPointBits = getFixedPointIBits(Ops.Ty) + getFixedPointFBits(Ops.Ty); + } + unsigned MSBBitShift = FixedPointBits - 1; + + // Number of data + s
[PATCH] D47017: [Fixed Point Arithmetic] Validation Test for Saturated Shift Left, Saturated Unsigned _Fract Types, and Fix for Saturated Unsigned Addition
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. This patch includes changes for the shift left operator involving saturated fixed point types. For unsigned shifting, overflow occurs if the number of bits we shift exceeds the number of leading zeros in the number. This number is found using the intrinsic llvm function `ctlz`. For signed shifting, if the number is positive, we cap at the max value for that type if the number of bits we shift exceeds the number of leading zeros. If the number is negative, we cap at the min value for that type if the number of bits we shift exceeds the number of leading ones. `ctlz` can be used in this case after flipping the bits in the number. - Saturation tests were also added for saturated unsigned _Fract types. - Added a fix to unsigned addition for saturated fixed point types where we would not be able to get the overflow if the number of data bits was equal to the underlying integer width. In this case, we need to use the intrinsic function `uadd.with.overflow` to detect overflow on this carry bit. This is a child of https://reviews.llvm.org/D47016 Repository: rC Clang https://reviews.llvm.org/D47017 Files: include/clang/AST/Type.h lib/CodeGen/CGExprScalar.cpp test/Frontend/fixed_point_all_builtin_operations.c Index: test/Frontend/fixed_point_all_builtin_operations.c === --- test/Frontend/fixed_point_all_builtin_operations.c +++ test/Frontend/fixed_point_all_builtin_operations.c @@ -105,6 +105,20 @@ a = -0.8 ## SUFFIX; \ b = 0.5 ## SUFFIX; \ ASSERT(a / b == -0.5 ## SUFFIX - 0.5 ## SUFFIX); \ +a = 0.1 ## SUFFIX; \ +ASSERT(a << 4 == 1.0 ## SUFFIX); \ +a = -0.8 ## SUFFIX; \ +ASSERT(a << 4 == -0.5 ## SUFFIX - 0.5 ## SUFFIX); \ + } + +#define FRACT_SATU_BINARY_OPS(TYPE, ID, SUFFIX) \ + { \ +TYPE a = 0.7 ## SUFFIX; \ +TYPE b = 0.9 ## SUFFIX; \ +ASSERT(a + b == 1.0 ## SUFFIX); \ +ASSERT(a - b == 0.0 ## SUFFIX); \ +ASSERT(b / a == 1.0 ## SUFFIX); \ +ASSERT(a << 1 == 1.0 ## SUFFIX); \ } int main(){ @@ -119,5 +133,9 @@ FRACT_SAT_BINARY_OPS(_Sat _Fract, SatFract, r); FRACT_SAT_BINARY_OPS(_Sat long _Fract, SatLongFract, lr); + FRACT_SATU_BINARY_OPS(_Sat unsigned short _Fract, SatUnsignedShortFract, uhr); + FRACT_SATU_BINARY_OPS(_Sat unsigned _Fract, SatUnsignedFract, ur); + FRACT_SATU_BINARY_OPS(_Sat unsigned long _Fract, SatUnsignedLongFract, ulr); + return 0; } Index: lib/CodeGen/CGExprScalar.cpp === --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -1144,7 +1144,9 @@ } // Ignore conversions like int -> uint. - if (SrcTy == DstTy) + // Except for fixed point types which may need radix transformations. + bool WorkingOnFixedPoints = DstType->isFixedPointType() && SrcType->isFixedPointType(); + if (SrcTy == DstTy && !WorkingOnFixedPoints) return Src; // Handle pointer conversions next: pointers can only be converted to/from @@ -1248,7 +1250,6 @@ DstTy = CGF.FloatTy; } - bool WorkingOnFixedPoints = DstType->isFixedPointType() && SrcType->isFixedPointType(); int order = WorkingOnFixedPoints ? CGF.getContext().getFixedPointTypeOrder(DstType, SrcType) : 0; if (WorkingOnFixedPoints && order < 0) { @@ -2876,7 +2877,7 @@ // Number of data + sign bits used in division unsigned DividendBits = FixedPointBits + fbits; - unsigned BitMask = (1 << DividendBits) - 1; + uint64_t BitMask = (static_cast<__int128_t>(1ULL) << DividendBits) - 1; llvm::Value *MaskedDivResult = Builder.CreateAnd(DivResult, BitMask); if (Ops.Ty->isSignedFixedPointType()) { @@ -3310,19 +3311,19 @@ llvm::Value *SatMinVal = llvm::ConstantInt::get( opTy, getFixedPointMinVal(op.Ty)); -unsigned MSBBitShift; if (op.Ty->isSignedFixedPointType()) { - MSBBitShift = getFixedPointIBits(op.Ty) + getFixedPointFBits(op.Ty); -} else { - MSBBitShift = getFixedPointIBits(op.Ty) + getFixedPointFBits(op.Ty) - 1; -} + unsigned MSBBitShift; + if (op.Ty->isSignedFixedPointType()) { +MSBBitShift = getFixedPointIBits(op.Ty) + getFixedPointFBits(op.Ty); + } else { +MSBBitShift = getFixedPointIBits(op.Ty) + getFixedPointFBits(op.Ty) - 1; + } -llvm::Value *Sum = Builder.CreateAdd(op.LHS, op.RHS); -llvm::Value *LHSMSB = Builder.CreateLShr(op.LHS, MSBBitShift); -llvm::Value *RHSMSB = Builder.CreateLShr(op.RHS, MSBBitShift); -llvm::Value *ResultMSB = Builder.CreateLShr(Sum, MSBBitShift); + llvm::Value *Sum = Builder.CreateAdd(op.LHS, op.RHS); + llvm::Value *LHSMSB = Builder.CreateLShr(op.LHS, MSBBitShift); + llvm::Value *RHSMSB = Builder.CreateLShr(op.RHS, MSBBitShift); + llvm::Value *ResultMSB = Builder.CreateLShr(Sum, MSBBit
[PATCH] D47030: [Fixed Point Arithmetic] Checks for Precision Macros
leonardchan created this revision. leonardchan added reviewers: phosek, mcgrathr, jakehehrlich. leonardchan added a project: clang. Herald added a subscriber: mgorny. This patch includes checks that the precision macros used for the fixed point fractional and integral bits meet the requirements for clause 6.2.6.3 in http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf. Checks for any disagreements with the recommendations will throw warnings. I also added my own warning that recommends the integral and fractional bits for _Accum types take up the width of the whole underlying integer to prevent having to mask out the padding bits when performing comparisons. Repository: rC Clang https://reviews.llvm.org/D47030 Files: cmake/modules/InitFixedPointBits.cmake Index: cmake/modules/InitFixedPointBits.cmake === --- cmake/modules/InitFixedPointBits.cmake +++ cmake/modules/InitFixedPointBits.cmake @@ -60,26 +60,170 @@ set(ULACCUM_IBIT 32) endif() -# Checks for each bit size +# Checks for each bit size defined in clause 6.2.6.3 + +# Cannot go below the minimum number of fractional and integral bits for the +# various types specified in clause 7.18a.3. +function(assert_min_bits macro min_bits) + set("macro_name" ${macro}) + set("macro_val" ${${macro}}) + if(${macro_val} LESS ${min_bits}) +message(FATAL_ERROR "The minimum value allowed for ${macro_name} is ${min_bits}. " + "${macro_val} was provided.") + endif() +endfunction() + +assert_min_bits(SFRACT_FBIT 7) +assert_min_bits(FRACT_FBIT 15) +assert_min_bits(LFRACT_FBIT 23) +assert_min_bits(USFRACT_FBIT 7) +assert_min_bits(UFRACT_FBIT 15) +assert_min_bits(ULFRACT_FBIT 23) + +assert_min_bits(SACCUM_FBIT 7) +assert_min_bits(ACCUM_FBIT 15) +assert_min_bits(LACCUM_FBIT 23) +assert_min_bits(USACCUM_FBIT 7) +assert_min_bits(UACCUM_FBIT 15) +assert_min_bits(ULACCUM_FBIT 23) + +assert_min_bits(SACCUM_IBIT 4) +assert_min_bits(ACCUM_IBIT 4) +assert_min_bits(LACCUM_IBIT 4) +assert_min_bits(USACCUM_IBIT 4) +assert_min_bits(UACCUM_IBIT 4) +assert_min_bits(ULACCUM_IBIT 4) + # Each unsigned fract type has either the same number of fractional bits as, # or one more fractional bit than, its corresponding signed fract type. -# TODO: Implement remaining checks in clause 6.2.6.3. -function(check_diff_at_most_1 sfract_fbits ufract_fbits) - if(sfract_fbits EQUAL ufract_fbits) -return() - endif() +function(assert_fract_diff sfract_fbits ufract_fbits) math(EXPR diff "${ufract_fbits} - ${sfract_fbits}") - if(diff EQUAL 1) -return() + if(NOT((${diff} EQUAL 0) OR (${diff} EQUAL 1))) +message(FATAL_ERROR "Each unsigned fract type must have either the same number of " + "fractional bits as, or one more fractional bit than, its corresponding " + "signed fract type.") + endif() +endfunction() + +assert_fract_diff(${SFRACT_FBIT} ${USFRACT_FBIT}) +assert_fract_diff(${FRACT_FBIT} ${UFRACT_FBIT}) +assert_fract_diff(${LFRACT_FBIT} ${ULFRACT_FBIT}) + +# When arranged in order of increasing rank (see 6.3.1.3a), the number of +# fractional bits is nondecreasing for each of the following sets of +# fixed-point types: +# - signed fract types +# - unsigned fract types +# - signed accum types +# - unsigned accum types. +function(assert_non_decreasing short_type_bits middle_type_bits long_type_bits + type_family bit_type) + if((${short_type_bits} GREATER ${middle_type_bits}) OR + (${middle_type_bits} GREATER ${long_type_bits})) +message(FATAL_ERROR "The number of ${bit_type} bits in ${type_family} types must be " + "non decreasing in order of increasing rank.") + endif() +endfunction() + +assert_non_decreasing(${SFRACT_FBIT} ${FRACT_FBIT} ${LFRACT_FBIT} "signed _Fract" "fractional") +assert_non_decreasing(${USFRACT_FBIT} ${UFRACT_FBIT} ${ULFRACT_FBIT} "unsigned _Fract" "fractional") +assert_non_decreasing(${SACCUM_FBIT} ${ACCUM_FBIT} ${LACCUM_FBIT} "signed _Accum" "fractional") +assert_non_decreasing(${USACCUM_FBIT} ${UACCUM_FBIT} ${ULACCUM_FBIT} "unsigned _Accum" "fractional") + +# When arranged in order of increasing rank (see 6.3.1.3a), the number of +# integral bits is nondecreasing for each of the following sets of +# fixed-point types: +# - signed accum types +# - unsigned accum types. +assert_non_decreasing(${SACCUM_IBIT} ${ACCUM_IBIT} ${LACCUM_IBIT} "signed _Accum" "integral") +assert_non_decreasing(${USACCUM_IBIT} ${UACCUM_IBIT} ${ULACCUM_IBIT} "unsigned _Accum" "integral") + +# Each signed accum type has at least as many integral bits as its +# corresponding unsigned accum type. +function(assert_integral_diff saccum_ibits uaccum_ibits) + if(${saccum_ibits} LESS ${uaccum_ibits}) +message(FATAL_ERROR "Each signed accum type must have at least as many integral bits as its " + "corresponding unsigned accum type.") + endif() +endfunction() + +assert_integral_diff(${SACCUM_IBIT} ${USACCUM_IBIT}) +assert_integral_diff(${ACCUM_IBIT} ${UACCUM_IBIT})
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 147386. leonardchan added a comment. Ran git-clang-tidy on all affected files Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -542,6 +548,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +// CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} accum '_Accum' +// CHECK-NEXT: `-VarDecl {{.*}} long_accum 'long _Accum' Index: lib/Serialization/ASTReader.cpp === --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6816,6 +6816,24 @@ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; +case PREDEF_TYPE_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; +case PREDEF_TYPE_ACCUM_ID: + T = Context.AccumTy; + break; +case PREDEF_TYPE_LONG_ACCUM_ID: + T = Co
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 147400. leonardchan added a comment. Added break. We still assign `Result` since it cannot be null at the end of the switch stmt, though the value doesn't matter. Added character `~` to indicate fixed point type followed by string detailing the type. I have not added a test to it because logically, I do not think we will ever reach that point. This logic is implemented in the `VisitType` method, which mostly gets called by visitors to c++ nodes like `VisitTemplateParameterList`, but we have disabled the use of fixed point types in c++. `VisitType` does get called in `VisitFunctionDecl` but the function exits early since we are not reading c++ (line lib/Index/USRGeneration.cpp:238). Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -542,6 +548,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +// CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} short_a
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan marked 2 inline comments as done. leonardchan added inline comments. Comment at: lib/Index/USRGeneration.cpp:691 +case BuiltinType::ULongAccum: + llvm_unreachable("No USR name mangling for fixed point types."); case BuiltinType::Float16: phosek wrote: > We need some solution for fixed point types. Added character ~ to indicate fixed point type followed by string detailing the type. I have not added a test to it because logically, I do not think we will ever reach that point. This logic is implemented in the VisitType method, which mostly gets called by visitors to c++ nodes like VisitTemplateParameterList, but we have disabled the use of fixed point types in c++. VisitType does get called in VisitFunctionDecl but the function exits early since we are not reading c++ (line lib/Index/USRGeneration.cpp:238). Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 147406. leonardchan marked an inline comment as done. leonardchan added a comment. Undid git-clang-formatting on ASTBitcodes.h Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -542,6 +548,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +// CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} accum '_Accum' +// CHECK-NEXT: `-VarDecl {{.*}} long_accum 'long _Accum' Index: lib/Serialization/ASTReader.cpp === --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6816,6 +6816,24 @@ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; +case PREDEF_TYPE_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; +case PREDEF_TYPE_ACCUM_ID: + T = Context.AccumTy; + break; +
[PATCH] D46911: [Fixed Point Arithmetic] Addition of the remaining fixed point types and their saturated equivalents
leonardchan updated this revision to Diff 147541. leonardchan added a comment. Updated formatting Repository: rC Clang https://reviews.llvm.org/D46911 Files: include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_errors.cpp Index: test/Frontend/fixed_point_errors.cpp === --- /dev/null +++ test/Frontend/fixed_point_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/fixed_point_errors.c === --- /dev/null +++ test/Frontend/fixed_point_errors.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} +unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} + +_Sat int i; // expected-error{{'int' cannot be saturated. Only _Fract and _Accum can.}} +_Sat _Sat _Fract fract; // expected-warning{{duplicate '_Sat' declaration specifier}} + +_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat unsigned long long _Accum sat_u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat long long _Fract sat_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +_Sat unsigned long long _Fract sat_u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} Index: test/Frontend/fixed_point.c === --- /dev/null +++ test/Frontend/fixed_point.c @@ -0,0 +1,82 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; +signed short _Fract s_short_fract; +signed _Fract s_fract; +signed long _Fract s_long_fract; +unsigned short _Fract u_short_fract; +unsigned _Fract u_fract; +unsigned long _Fract u_long_fract; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; +short _Fract short_fract; +_Fract fract; +long _Fract long_fract; + +// Saturated fixed point types +_Sat signed short _Accum sat_s_short_accum; +_Sat signed _Accum sat_s_accum; +_Sat signed long _Accum sat_s_long_accum; +_Sat unsigned short _Accum sat_u_short_accum; +_Sat unsigned _Accum sat_u_accum; +_Sat unsigned long _Accum sat_u_long_accum; +_Sat signed short _Fract sat_s_short_fract; +_Sat signed _Fract sat_s_fract; +_Sat signed long _Fract sat_s_long_fract; +_Sat unsigned short _Fract sat_u_short_fract; +_Sat unsigned _Fract sat_u_fract; +_Sat unsigned long _Fract sat_u_long_fract; + +// Aliased saturated fixed point types +_Sat short _Accum sat_short_accum; +_Sat _Accum sat_accum; +_Sat l
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 147549. Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -542,6 +548,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +// CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} accum '_Accum' +// CHECK-NEXT: `-VarDecl {{.*}} long_accum 'long _Accum' Index: lib/Serialization/ASTReader.cpp === --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6816,6 +6816,24 @@ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; +case PREDEF_TYPE_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; +case PREDEF_TYPE_ACCUM_ID: + T = Context.AccumTy; + break; +case PREDEF_TYPE_LONG_ACCUM_ID: + T = Context.LongAccumTy; + break; +case PREDEF_TYPE_USHORT_ACCUM_ID:
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 147560. Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -542,6 +548,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +// CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} accum '_Accum' +// CHECK-NEXT: `-VarDecl {{.*}} long_accum 'long _Accum' Index: lib/Serialization/ASTReader.cpp === --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6816,6 +6816,24 @@ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; +case PREDEF_TYPE_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; +case PREDEF_TYPE_ACCUM_ID: + T = Context.AccumTy; + break; +case PREDEF_TYPE_LONG_ACCUM_ID: + T = Context.LongAccumTy; + break; +case PREDEF_TYPE_USHORT_ACCUM_ID:
[PATCH] D46911: [Fixed Point Arithmetic] Addition of the remaining fixed point types and their saturated equivalents
leonardchan updated this revision to Diff 147566. Repository: rC Clang https://reviews.llvm.org/D46911 Files: include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_errors.cpp Index: test/Frontend/fixed_point_errors.cpp === --- /dev/null +++ test/Frontend/fixed_point_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/fixed_point_errors.c === --- /dev/null +++ test/Frontend/fixed_point_errors.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} +unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} + +_Sat int i; // expected-error{{'int' cannot be saturated. Only _Fract and _Accum can.}} +_Sat _Sat _Fract fract; // expected-warning{{duplicate '_Sat' declaration specifier}} + +_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat unsigned long long _Accum sat_u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat long long _Fract sat_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +_Sat unsigned long long _Fract sat_u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} Index: test/Frontend/fixed_point.c === --- /dev/null +++ test/Frontend/fixed_point.c @@ -0,0 +1,82 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; +signed short _Fract s_short_fract; +signed _Fract s_fract; +signed long _Fract s_long_fract; +unsigned short _Fract u_short_fract; +unsigned _Fract u_fract; +unsigned long _Fract u_long_fract; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; +short _Fract short_fract; +_Fract fract; +long _Fract long_fract; + +// Saturated fixed point types +_Sat signed short _Accum sat_s_short_accum; +_Sat signed _Accum sat_s_accum; +_Sat signed long _Accum sat_s_long_accum; +_Sat unsigned short _Accum sat_u_short_accum; +_Sat unsigned _Accum sat_u_accum; +_Sat unsigned long _Accum sat_u_long_accum; +_Sat signed short _Fract sat_s_short_fract; +_Sat signed _Fract sat_s_fract; +_Sat signed long _Fract sat_s_long_fract; +_Sat unsigned short _Fract sat_u_short_fract; +_Sat unsigned _Fract sat_u_fract; +_Sat unsigned long _Fract sat_u_long_fract; + +// Aliased saturated fixed point types +_Sat short _Accum sat_short_accum; +_Sat _Accum sat_accum; +_Sat long _Accum sat_long_accum; +_Sat short _Fract sat_
[PATCH] D46911: [Fixed Point Arithmetic] Addition of the remaining fixed point types and their saturated equivalents
leonardchan updated this revision to Diff 147568. Repository: rC Clang https://reviews.llvm.org/D46911 Files: include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_errors.cpp Index: test/Frontend/fixed_point_errors.cpp === --- /dev/null +++ test/Frontend/fixed_point_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum;// expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/fixed_point_errors.c === --- /dev/null +++ test/Frontend/fixed_point_errors.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} +unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} + +_Sat int i; // expected-error{{'int' cannot be saturated. Only _Fract and _Accum can.}} +_Sat _Sat _Fract fract; // expected-warning{{duplicate '_Sat' declaration specifier}} + +_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat unsigned long long _Accum sat_u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat long long _Fract sat_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +_Sat unsigned long long _Fract sat_u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} Index: test/Frontend/fixed_point.c === --- /dev/null +++ test/Frontend/fixed_point.c @@ -0,0 +1,82 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; +signed short _Fract s_short_fract; +signed _Fract s_fract; +signed long _Fract s_long_fract; +unsigned short _Fract u_short_fract; +unsigned _Fract u_fract; +unsigned long _Fract u_long_fract; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; +short _Fract short_fract; +_Fract fract; +long _Fract long_fract; + +// Saturated fixed point types +_Sat signed short _Accum sat_s_short_accum; +_Sat signed _Accum sat_s_accum; +_Sat signed long _Accum sat_s_long_accum; +_Sat unsigned short _Accum sat_u_short_accum; +_Sat unsigned _Accum sat_u_accum; +_Sat unsigned long _Accum sat_u_long_accum; +_Sat signed short _Fract sat_s_short_fract; +_Sat signed _Fract sat_s_fract; +_Sat signed long _Fract sat_s_long_fract; +_Sat unsigned short _Fract sat_u_short_fract; +_Sat unsigned _Fract sat_u_fract; +_Sat unsigned long _Fract sat_u_long_fract; + +// Aliased saturated fixed point types +_Sat short _Accum sat_short_accum; +_Sat _Accum sat_accum; +_Sat long _Accum sat_long_accum; +_Sat short _Fract sat_
[PATCH] D46915: [Fixed Point Arithmetic] Set Fixed Point Precision Bits and Create Fixed Point Literals
leonardchan updated this revision to Diff 147595. leonardchan added a comment. formatting Repository: rC Clang https://reviews.llvm.org/D46915 Files: CMakeLists.txt cmake/modules/InitFixedPointBits.cmake include/clang/AST/Expr.h include/clang/AST/OperationKinds.def include/clang/AST/RecursiveASTVisitor.h include/clang/AST/Type.h include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/FixedPoint.h.in include/clang/Basic/StmtNodes.td include/clang/Lex/LiteralSupport.h lib/AST/ASTContext.cpp lib/AST/ASTDumper.cpp lib/AST/Expr.cpp lib/AST/ExprClassification.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtProfile.cpp lib/AST/Type.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Lex/LiteralSupport.cpp lib/Sema/Sema.cpp lib/Sema/SemaExceptionSpec.cpp lib/Sema/SemaExpr.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_declarations.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_validation.c tools/libclang/CXCursor.cpp Index: tools/libclang/CXCursor.cpp === --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -305,6 +305,10 @@ K = CXCursor_IntegerLiteral; break; + case Stmt::FixedPointLiteralClass: +llvm_unreachable("No cursor for FixedPointLiteralClass"); +break; + case Stmt::FloatingLiteralClass: K = CXCursor_FloatingLiteral; break; Index: test/Frontend/fixed_point_validation.c === --- /dev/null +++ test/Frontend/fixed_point_validation.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli + +// Run simple validation tests + +#define assert(b) if (!(b)) { return 1; } + +int main(){ + short _Accum s_accum; + short _Accum s_accum2 = 2.0hk; + short _Fract s_fract = 0.999hr; + short _Fract s_fract2 = -0.999hr; + + assert(s_accum == 0); + + s_accum = s_accum2; + + assert(s_accum == s_accum2); + assert(s_accum == 2); +} Index: test/Frontend/fixed_point_errors.c === --- test/Frontend/fixed_point_errors.c +++ test/Frontend/fixed_point_errors.c @@ -1,14 +1,23 @@ // RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s -long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} -unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} -long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} -unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} +unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} _Sat int i; // expected-error{{'int' cannot be saturated. Only _Fract and _Accum can.}} _Sat _Sat _Fract fract; // expected-warning{{duplicate '_Sat' declaration specifier}} -_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} _Sat unsigned long long _Accum sat_u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} -_Sat long long _Fract sat_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +_Sat long long _Fract sat_longlong_fract; // expected-error{{'long long _Fract' is invalid}} _Sat unsigned long long _Fract sat_u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} + +short _Fract fract2 = 1.2hr; // expected-error{{a _Fract type cannot have an integral part}} + +signed short _Accum s_short_accum = 129.0hk; // expected-error{{the integral part of this literal is too large for this signed _Accum type}} +unsigned short _Accum u_short_accum = 256.0uhk; // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}} +signed _Accum s_accum = 32770.0k; // expected-error{{the integral part of this literal is too large for this signed _Accum type}} +unsigned _Accum u_accum = 65536.0uk; // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}} +short _Accum short_accum = 129.0hk; // expected-error{{the integr
[PATCH] D46917: [Fixed Point Arithmetic] Comparison and Unary Operations for Fixed Point Types
leonardchan updated this revision to Diff 147631. leonardchan added a comment. formatting Repository: rC Clang https://reviews.llvm.org/D46917 Files: lib/CodeGen/CGExprScalar.cpp lib/Sema/SemaExpr.cpp test/Frontend/fixed_point_declarations.c test/Frontend/fixed_point_validation.c Index: test/Frontend/fixed_point_validation.c === --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -1,19 +1,170 @@ +// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -S -emit-llvm -o - %s | lli +// The first test checks the emitted llvm IR. +// The second test checks the output. +// Both these test require that the default bit widths for the fixed point types +// are used since we check for bit shifted literals that were converted from +// ints and floats. + +// Primary fixed point types +signed short _Accum s_short_accum;// CHECK-DAG: @s_short_accum = common dso_local global i16 0, align 2 +signed _Accum s_accum;// CHECK-DAG: @s_accum =common dso_local global i32 0, align 4 +signed long _Accum s_long_accum; // CHECK-DAG: @s_long_accum = common dso_local global i64 0, align 8 +unsigned short _Accum u_short_accum; // CHECK-DAG: @u_short_accum = common dso_local global i16 0, align 2 +unsigned _Accum u_accum; // CHECK-DAG: @u_accum =common dso_local global i32 0, align 4 +unsigned long _Accum u_long_accum;// CHECK-DAG: @u_long_accum = common dso_local global i64 0, align 8 +signed short _Fract s_short_fract;// CHECK-DAG: @s_short_fract = common dso_local global i16 0, align 2 +signed _Fract s_fract;// CHECK-DAG: @s_fract =common dso_local global i32 0, align 4 +signed long _Fract s_long_fract; // CHECK-DAG: @s_long_fract = common dso_local global i64 0, align 8 +unsigned short _Fract u_short_fract; // CHECK-DAG: @u_short_fract = common dso_local global i16 0, align 2 +unsigned _Fract u_fract; // CHECK-DAG: @u_fract =common dso_local global i32 0, align 4 +unsigned long _Fract u_long_fract;// CHECK-DAG: @u_long_fract = common dso_local global i64 0, align 8 + +// There are 7 bits allocated to the fractional part and 8 +// bits allocated to the integral part of a short _Accum by default. + +signed short _Accum s_short_accum2 = 2.5hk; // CHECK-DAG: @s_short_accum2 = dso_local global i16 320, align 2 +short _Fract short_fract = 0.333hr; // CHECK-DAG: @short_fract = dso_local global i16 42, align 2 + // Run simple validation tests #define assert(b) if (!(b)) { return 1; } int main(){ - short _Accum s_accum; + short _Accum s_accum = 0.0hk; short _Accum s_accum2 = 2.0hk; short _Fract s_fract = 0.999hr; short _Fract s_fract2 = -0.999hr; + const _Fract fract_zero = 0.0r; + // CHECK: %s_accum = alloca i16, align 2 + // CHECK: %s_accum2 = alloca i16, align 2 + // CHECK: %s_fract = alloca i16, align 2 + // CHECK: %s_fract2 = alloca i16, align 2 + // CHECK: %fract_zero = alloca i32, align 4 + // CHECK: store i16 0, i16* %s_accum, align 2 + // CHECK: store i16 256, i16* %s_accum2, align 2 + // CHECK: store i16 127, i16* %s_fract, align 2 + // CHECK: store i16 -127, i16* %s_fract2, align 2 + // CHECK: store i32 0, i32* %fract_zero, align 4 + + / Simple Comparisons ***/ assert(s_accum == 0); + // CHECK: {{.*}} = load i16, i16* %s_accum, align 2 + // CHECK-NEXT: {{.*}} = icmp eq i16 {{.*}}, 0 s_accum = s_accum2; + // CHECK: {{.*}} = load i16, i16* %s_accum2, align 2 + // CHECK-NEXT: store i16 %1, i16* %s_accum, align 2 assert(s_accum == s_accum2); + // CHECK: {{.*}} = load i16, i16* %s_accum, align 2 + // CHECK-NEXT: {{.*}} = load i16, i16* %s_accum2, align 2 + // CHECK-NEXT: {{.*}} = icmp eq i16 {{.*}}, {{.*}} + + assert(s_accum2 == s_accum); + // CHECK: {{.*}} = load i16, i16* %s_accum2, align 2 + // CHECK-NEXT: {{.*}} = load i16, i16* %s_accum, align 2 + // CHECK-NEXT: {{.*}} = icmp eq i16 {{.*}}, {{.*}} + assert(s_accum == 2); + // CHECK: {{.*}} = icmp eq i16 {{.*}}, 256 + + assert(2 == s_accum); + // CHECK: {{.*}} = icmp eq i16 256, {{.*}} + + int x = 2; + assert(s_accum == x); + // CHECK: {{.*}} = load i32, i32* %x, align 4 + // CHECK-NEXT: {{.*}} = trunc i32 {{.*}} to i16 + // CHECK-NEXT: {{.*}} = shl i16 {{.*}}, 7 + // CHECK-NEXT: {{.*}} = icmp eq i16 {{.*}}, {{.*}} + + assert(x == s_accum); + + assert(s_accum != -2); + // CHECK: {{.*}} = icmp ne i16 {{.*}}, -256 + + assert(-2 != s_accum); + // CHECK: {{.*}} = icmp ne i16 -256, {{.*}} + + assert(s_accum != -x); + assert(-x != s_accum); + + assert(s_fract != 1); + // CHECK: {{.*}} = load i16, i16* %s_fract, align 2 + // CHECK_NEXT: {{.*}} = icmp ne i16 {{.*}}, 128 + + assert(s_fract2 != -1); + // CHECK: {
[PATCH] D46925: [Fixed Point Arithmetic] Remaining Binary Operations on Primary Fixed Point Types
leonardchan updated this revision to Diff 147880. leonardchan added a comment. formatting Repository: rC Clang https://reviews.llvm.org/D46925 Files: include/clang/AST/ASTContext.h include/clang/AST/OperationKinds.def include/clang/AST/Type.h lib/AST/ASTContext.cpp lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/AST/Type.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_validation.c Index: test/Frontend/fixed_point_validation.c === --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -74,6 +74,9 @@ assert(2 == s_accum); // CHECK: {{.*}} = icmp eq i16 256, {{.*}} + assert(2 == 2.0hk); + assert(2 != 2.01hk); + int x = 2; assert(s_accum == x); // CHECK: {{.*}} = load i32, i32* %x, align 4 @@ -128,6 +131,46 @@ // numbers. assert(2 == 2.001hk); // This is valid if SACCUM_FBITS == 7 + // Comparisons between fixed-point types + // Signed _Accum to signed _Accum types. + assert(2.5hk == 2.5k); + assert(2.5k == 2.5lk); + assert(-2.5hk == -2.5k); + assert(-2.5k == -2.5lk); + + // Unsigned _Accum to unigned _Accum + assert(2.5uhk == 2.5uk); + assert(2.5uk == 2.5ulk); + + // Signed _Fract to signed _Fract types. + assert(0.333hr != 0.333r); // Loss of precision since different fractional widths + assert(0.333r != 0.333lr); + assert(-0.333hr != -0.333r); + assert(-0.333r != -0.333lr); + + // Unsigned _Fract to unsigned _Fract types. + assert(0.333uhr != 0.333ur); + assert(0.333ur != 0.333ulr); + + // Signed _Accum to signed _Fract + assert(0.333hk == 0.333hr); + assert(0.333k == 0.333r); + assert(0.333lk == 0.333lr); + assert(0.333hk == 0.333r); // Although _Fract has higher precision, it gets casted up to + // short _Accum which (using default precisions) + // has fewer fractional bits. + + // Signed _Accum to unsigned _Fract + assert(0.333hk == 0.333uhr); + assert(0.333k == 0.333ur); + assert(0.333lk == 0.333ulr); + + // Signed _Accum to unsigned _Accum + assert(2.5hk == 2.5uhk); + assert(2.5k == 2.5uk); + assert(2.5lk == 2.5ulk); + + / Unary operations ***/ s_accum = 0.0hk; @@ -167,4 +210,58 @@ assert(+s_fract == s_fract); assert(+s_fract2 == s_fract2); // s_fract2 is negative assert(-s_fract == s_fract2); + + / Binary operations ***/ + + // Addition + s_accum = 3.0hk; + short _Accum s_accum_sum = s_accum + s_accum2; + assert(s_accum_sum == 5); + assert(s_fract + s_fract2 == 0); + + // Subtraction + short _Accum s_accum_diff = s_accum - s_accum2; + assert(s_accum_diff == 1); + assert(s_accum2 - s_accum == -1); + + // Multiplication + short _Accum s_accum_mul = s_accum * s_accum2; + assert(s_accum_mul == 6); + assert(2.0hk * 3.0hk == 6); + assert(2.0hk * 3 == 6); + assert(2.5hk * 3 == 7.5k); + assert(-2.5hk * 3 == -7.5lk); + assert(3 * -2.5hk == -7.5hk); + assert(-2.5hk * 0 == 0); + + // Division + const short _Accum s_accum3 = 2.5hk; + short _Accum s_accum_div = s_accum3 / s_accum2; + assert(s_accum_div == 1.25hk); + assert(5.0hk / s_accum3 == 2); + assert(-5.0hk / s_accum3 == -2); + assert(9.9k / 3.3k == 3); + assert(9.9hk / 3.3k != 3); // We lose precision when converting between types of different + // fractional width. + assert(6.75hk / 2.25k == 3); // Unless the fractional part can be evenly represented with +// sums of powers of 2. + assert(0 / 2.0hk == 0); + + // Left shift + short _Accum s_accum_shl = s_accum2 << 3; + assert(s_accum_shl == 16); + assert(1.0hk << 3 == 8); + assert(-1.0hk << 3 == -8); + assert(1.5k << 1 == 3); // LShift is equivalent to multiplying by 2 + assert(-1.25hk << 2 == -5); + + // Right shift + const signed short _Accum s_accum4 = 16.0hk; + short _Accum s_accum_shr = s_accum4 >> 3; + assert(s_accum_shr == 2); + assert(s_accum_shr >> 1 == 1); + assert(s_accum_shr >> 2 == 0.5hr); // RShift is equivalent to dividing by 2 + assert(5.0hk >> 2 == 1.25hk); + assert(-5.0hk >> 2 == -1.25k); + assert(0.0hr >> 2 == 0); } Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp === --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -321,6 +321,8 @@ const LocationContext *LCtx = Pred->getLocationContext(); switch (CastE->getCastKind()) { + case CK_FixedPointCast: +llvm_unreachable("CK_FixedPointCast"); // TODO case CK_IntegralToFixedPoint: llvm_unreachable( "ExprEngine::VisitCast CK_IntegralToF
[PATCH] D46926: [Fixed Point Arithmetic] Conversion between Fixed Point and Floating Point Numbers
leonardchan updated this revision to Diff 147881. leonardchan added a comment. formatting Repository: rC Clang https://reviews.llvm.org/D46926 Files: include/clang/AST/OperationKinds.def include/clang/Basic/DiagnosticSemaKinds.td lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/SemaCast.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_validation.c Index: test/Frontend/fixed_point_validation.c === --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -30,6 +30,7 @@ // Run simple validation tests #define assert(b) if (!(b)) { return 1; } +#define abs(x) x < 0 ? -x : x int main(){ short _Accum s_accum = 0.0hk; @@ -264,4 +265,18 @@ assert(5.0hk >> 2 == 1.25hk); assert(-5.0hk >> 2 == -1.25k); assert(0.0hr >> 2 == 0); + + / Float conversions ***/ + + float f = (float)2.5k; + assert(f > 2.4999 && f < 2.5001); // High precision since the fractional + // value can be evenly represented. + assert((float)2.333hk != 2.333f); + + float base = 2.333f; + float saccum_diff = abs(base - 2.333hk); + float accum_diff = abs(base - 2.333k); + float laccum_diff = abs(base - 2.333lk); + assert(accum_diff < saccum_diff); + assert(laccum_diff < accum_diff); } Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp === --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -326,6 +326,8 @@ case CK_IntegralToFixedPoint: llvm_unreachable( "ExprEngine::VisitCast CK_IntegralToFixedPoint"); // TODO + case CK_FixedPointToFloating: +llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_LValueToRValue: llvm_unreachable("LValueToRValue casts handled earlier."); case CK_ToVoid: Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -1029,6 +1029,21 @@ return result; } +/// \brief Handle arithmetic conversion from fixed point to floating. Helper +/// function of UsualArithmeticConversions() +static QualType handleFixedPointToFloatConversion(Sema &S, + ExprResult &FloatExpr, + ExprResult &FixedPointExpr, + QualType FloatTy, + QualType FixedPointTy) { + assert(FloatTy->isFloatingType()); + assert(FixedPointTy->isFixedPointType()); + + FixedPointExpr = S.ImpCastExprToType(FixedPointExpr.get(), FloatTy, + CK_FixedPointToFloating); + return FloatTy; +} + /// \brief Handle arithmethic conversion with floating point types. Helper /// function of UsualArithmeticConversions() static QualType handleFloatConversion(Sema &S, ExprResult &LHS, @@ -1057,11 +1072,20 @@ if (LHSType->isHalfType() && !S.getLangOpts().NativeHalfType) LHSType = S.Context.FloatTy; +if (RHSType->isFixedPointType()) { + return handleFixedPointToFloatConversion(S, LHS, RHS, LHSType, RHSType); +} + return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType, /*convertFloat=*/!IsCompAssign, /*convertInt=*/ true); } assert(RHSFloat); + + if (LHSType->isFixedPointType()) { +return handleFixedPointToFloatConversion(S, RHS, LHS, RHSType, LHSType); + } + return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType, /*convertInt=*/ true, /*convertFloat=*/!IsCompAssign); @@ -1218,6 +1242,7 @@ CK_IntegralRealToComplex); return ComplexType; } + /// \brief Handle arithmetic conversion from integer to fixed point. Helper /// function of UsualArithmeticConversions() static QualType handleIntToFixedPointConversion(Sema &S, @@ -6041,9 +6066,20 @@ } llvm_unreachable("Should have returned before this"); - case Type::STK_FixedPoint: -llvm_unreachable( -"Sema::PrepareScalarCast from STK_FixedPoint to anything"); // TODO + case Type::STK_FixedPoint: { +switch (DestTy->getScalarTypeKind()) { + default: +llvm_unreachable("Unable to convert from fixed point type"); + case Type::STK_Integral: +llvm_unreachable( +"Unimplemented scalar cast from fixed point to int"); // TODO + case Type::STK_Floating: +return CK_FixedPointToFloat
[PATCH] D46927: [Fixed Point Arithmetic] Augmented Assignment for Fixed Point Types
leonardchan updated this revision to Diff 147882. leonardchan added a comment. formatting Repository: rC Clang https://reviews.llvm.org/D46927 Files: include/clang/AST/Type.h lib/AST/Type.cpp lib/CodeGen/CGExprScalar.cpp lib/Sema/SemaExpr.cpp test/Frontend/fixed_point_validation.c Index: test/Frontend/fixed_point_validation.c === --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -1,5 +1,5 @@ -// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -S -emit-llvm -o - %s | lli +// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s // The first test checks the emitted llvm IR. // The second test checks the output. @@ -279,4 +279,35 @@ float laccum_diff = abs(base - 2.333lk); assert(accum_diff < saccum_diff); assert(laccum_diff < accum_diff); + + / Auxillary assignments ***/ + + s_accum = 7.5hk; + s_accum2 = 2.0hk; + s_accum += s_accum2; + assert(s_accum == 9.5hk); + s_accum += 2.5k; + assert(s_accum == 12); + + s_accum -= s_accum2; + assert(s_accum == 10); + s_accum -= 2.5lk; + assert(s_accum == 7.5k); + + s_accum2 = 3.0k; + s_accum *= s_accum2; + assert(s_accum == 22.5k); + s_accum *= 0.5r; + assert(s_accum == 11.25hk); + + s_accum /= s_accum2; + assert(s_accum == 3.75k); + s_accum /= 0.5hr; + assert(s_accum == 7.5k); + + s_accum <<= 3; + assert(s_accum == 60); + + s_accum >>= 3; + assert(s_accum == 7.5k); } Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -6076,8 +6076,7 @@ case Type::STK_Floating: return CK_FixedPointToFloating; case Type::STK_FixedPoint: -llvm_unreachable( -"Unimplemented scalar cast from fixed point to fixed point"); // TODO +return CK_FixedPointCast; } } Index: lib/CodeGen/CGExprScalar.cpp === --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -308,6 +308,17 @@ Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy, SourceLocation Loc, bool TreatBooleanAsSigned); + /// Emit a conversion between fixed point types by moving the radix point. + /// This does not take into account resizing of the underlying llvm type + /// which should be handled either before or after calling this function. + /// + /// If the type is being scaled up, this method should be called after + /// performing an intcast. If the type is scaled down, this method should be + /// called before performing an intcast. This is necessary such that the + /// shift operations retain as much of the original data as possible before + /// truncation or after extension. + Value *EmitFixedPointRadixShift(Value *Src, QualType SrcTy, QualType DstTy); + /// Emit a conversion from the specified complex type to the specified /// destination type, where the destination type is an LLVM scalar type. Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, @@ -961,6 +972,49 @@ SanitizerHandler::FloatCastOverflow, StaticArgs, OrigSrc); } +/// Emit a conversion between fixed point types by moving the radix point. +/// This does not take into account resizing of the underlying llvm type +/// which should be handled either before or after calling this function. +/// +/// If the type is being scaled up, this method should be called after +/// performing an intcast. If the type is scaled down, this method should be +/// called before performing an intcast. This is necessary such that the +/// shift operations retain as much of the original data as possible before +/// truncation or after extension. +Value *ScalarExprEmitter::EmitFixedPointRadixShift(Value *Src, QualType SrcTy, + QualType DstTy) { + assert(DstTy->isFixedPointType()); + assert(SrcTy->isFixedPointType()); + + Value *Res = Src; + + // Casting between fixed point types involves separating the integral and + // fractional bits, potentially shifting them, then joining back together. + unsigned dest_fbits = getFixedPointFBits(DstTy); + unsigned src_fbits = getFixedPointFBits(SrcTy); + unsigned dest_ibits = getFixedPointIBits(DstTy); + unsigned src_ibits = getFixedPointIBits(SrcTy); + + // If the number of integral bits is decreasing, trim off any extra bits while + // retaining the sign. + if (dest_ibits < src_ibits) { +Res = Builder.CreateShl(Res, src_ibits - dest_ibits); +Res = Builder.CreateAShr(Res, src_ibits - dest_ibits); + } + + // Move the radix. For irrational numbers, there will be loss of precision + // using this method when the number of fbits increases since we will be right + // padding zeros. Precision can still be retained if we temporarily convert to
[PATCH] D46960: [Fixed Point Arithmetic] Predefined Precision Macros
leonardchan updated this revision to Diff 147883. leonardchan added a comment. formatting Repository: rC Clang https://reviews.llvm.org/D46960 Files: include/clang/Lex/Preprocessor.h lib/Lex/PPMacroExpansion.cpp test/Frontend/fixed_point_builtin_macros.c Index: test/Frontend/fixed_point_builtin_macros.c === --- /dev/null +++ test/Frontend/fixed_point_builtin_macros.c @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli + +#define assert(b) if (!(b)) { return 1; } + +int main() { + // Test using the recommended values for a typical desktop processor (Annex + // A.3). These are also the default values when building clang. + // Fractional bits of _Accum types + assert(__SACCUM_FBIT__ == 7); + assert(__ACCUM_FBIT__ == 15); + assert(__LACCUM_FBIT__ == 31); + assert(__USACCUM_FBIT__ == 8); + assert(__UACCUM_FBIT__ == 16); + assert(__ULACCUM_FBIT__ == 32); + + // Fractional bits of _Fract types + assert(__SFRACT_FBIT__ == 7); + assert(__FRACT_FBIT__ == 15); + assert(__LFRACT_FBIT__ == 31); + assert(__USFRACT_FBIT__ == 8); + assert(__UFRACT_FBIT__ == 16); + assert(__ULFRACT_FBIT__ == 32); + + // Integral bits of _Accum types + assert(__SACCUM_IBIT__ == 8); + assert(__ACCUM_IBIT__ == 16); + assert(__LACCUM_IBIT__ == 32); + assert(__USACCUM_IBIT__ == 8); + assert(__UACCUM_IBIT__ == 16); + assert(__ULACCUM_IBIT__ == 32); +} Index: lib/Lex/PPMacroExpansion.cpp === --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -14,6 +14,7 @@ #include "clang/Basic/Attributes.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/FixedPoint.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -355,6 +356,31 @@ Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__"); Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__"); + // Fixed point macros (ISO/IEC JTC1 SC22 WG14 N1169) + // Fractional bits of _Accum types + Ident__SACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__SACCUM_FBIT__"); + Ident__ACCUM_FBIT__= RegisterBuiltinMacro(*this, "__ACCUM_FBIT__"); + Ident__LACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__LACCUM_FBIT__"); + Ident__USACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__USACCUM_FBIT__"); + Ident__UACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__UACCUM_FBIT__"); + Ident__ULACCUM_FBIT__ = RegisterBuiltinMacro(*this, "__ULACCUM_FBIT__"); + + // Fractional bits of _Fract types + Ident__SFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__SFRACT_FBIT__"); + Ident__FRACT_FBIT__= RegisterBuiltinMacro(*this, "__FRACT_FBIT__"); + Ident__LFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__LFRACT_FBIT__"); + Ident__USFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__USFRACT_FBIT__"); + Ident__UFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__UFRACT_FBIT__"); + Ident__ULFRACT_FBIT__ = RegisterBuiltinMacro(*this, "__ULFRACT_FBIT__"); + + // Integral bits of _Accum types + Ident__SACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__SACCUM_IBIT__"); + Ident__ACCUM_IBIT__= RegisterBuiltinMacro(*this, "__ACCUM_IBIT__"); + Ident__LACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__LACCUM_IBIT__"); + Ident__USACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__USACCUM_IBIT__"); + Ident__UACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__UACCUM_IBIT__"); + Ident__ULACCUM_IBIT__ = RegisterBuiltinMacro(*this, "__ULACCUM_IBIT__"); + // Microsoft Extensions. if (LangOpts.MicrosoftExt) { Ident__identifier = RegisterBuiltinMacro(*this, "__identifier"); @@ -1696,6 +1722,68 @@ // __LINE__ expands to a simple numeric value. OS << (PLoc.isValid()? PLoc.getLine() : 1); Tok.setKind(tok::numeric_constant); + + // Fixed point macros + // Fractional bits of _Accum types + } else if (II == Ident__SACCUM_FBIT__) { +OS << BUILTIN_SACCUM_FBIT; +Tok.setKind(tok::numeric_constant); + } else if (II == Ident__ACCUM_FBIT__) { +OS << BUILTIN_ACCUM_FBIT; +Tok.setKind(tok::numeric_constant); + } else if (II == Ident__LACCUM_FBIT__) { +OS << BUILTIN_LACCUM_FBIT; +Tok.setKind(tok::numeric_constant); + } else if (II == Ident__USACCUM_FBIT__) { +OS << BUILTIN_USACCUM_FBIT; +Tok.setKind(tok::numeric_constant); + } else if (II == Ident__UACCUM_FBIT__) { +OS << BUILTIN_UACCUM_FBIT; +Tok.setKind(tok::numeric_constant); + } else if (II == Ident__ULACCUM_FBIT__) { +OS << BUILTIN_ULACCUM_FBIT; +Tok.setKind(tok::numeric_constant); + + // Fractional bits of _Fract types + } else if (II == Ident__SFRACT_FBIT__) { +OS << BUILTIN_SFRACT_FBIT; +Tok.setKind(tok::numeric_constant); + } else if (II == Ident__FRACT_FBIT__) { +OS << BUILTIN_FRACT_FBIT; +Tok.setKind(tok::numeric_constant); + } else if (II == Ident__LFRACT_FBIT__) { +OS << BUILTIN_LFRA
[PATCH] D46963: [Fixed Point Arithmetic] Test for All Builtin Operations
leonardchan updated this revision to Diff 147888. leonardchan added a comment. formatting Repository: rC Clang https://reviews.llvm.org/D46963 Files: lib/AST/ASTContext.cpp lib/CodeGen/CGExprScalar.cpp test/Frontend/fixed_point_all_builtin_operations.c Index: test/Frontend/fixed_point_all_builtin_operations.c === --- /dev/null +++ test/Frontend/fixed_point_all_builtin_operations.c @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -Werror %s + +// Check that we can use all supported binary and unary operations according to +// clause 4.1.6 in N1169. + +#define ALL_OPERATIONS_FOR_TYPE(TYPE, ID) \ + TYPE unary_add##ID(TYPE a) { return +a; } \ + TYPE unary_sub##ID(TYPE a) { return -a; } \ + int logical_not##ID(TYPE a) { return !a; } \ + TYPE add##ID(TYPE a, TYPE b) { return a + b; } \ + TYPE sub##ID(TYPE a, TYPE b) { return a - b; } \ + TYPE mul##ID(TYPE a, TYPE b) { return a * b; } \ + TYPE div##ID(TYPE a, TYPE b) { return a / b; } \ + TYPE shl##ID(TYPE a, int b) { return a << b; } \ + TYPE shr##ID(TYPE a, int b) { return a >> b; } \ + TYPE augmented_add##ID(TYPE a, TYPE b) {\ +a += b; \ +return a; \ + } \ + TYPE augmented_sub##ID(TYPE a, TYPE b) {\ +a -= b; \ +return a; \ + } \ + TYPE augmented_mul##ID(TYPE a, TYPE b) {\ +a *= b; \ +return a; \ + } \ + TYPE augmented_div##ID(TYPE a, TYPE b) {\ +a /= b; \ +return a; \ + } \ + TYPE augmented_shl##ID(TYPE a, int b) { \ +a <<= b; \ +return a; \ + } \ + TYPE augmented_shr##ID(TYPE a, int b) { \ +a >>= b; \ +return a; \ + } \ + int eq##ID(TYPE a, TYPE b) { return a == b; } \ + int ne##ID(TYPE a, TYPE b) { return a != b; } \ + int lt##ID(TYPE a, TYPE b) { return a < b; }\ + int le##ID(TYPE a, TYPE b) { return a <= b; } \ + int ge##ID(TYPE a, TYPE b) { return a >= b; } \ + int gt##ID(TYPE a, TYPE b) { return a > b; }\ + TYPE pre_inc##ID(TYPE a) { return ++a; }\ + TYPE pre_dec##ID(TYPE a) { return --a; }\ + TYPE post_inc##ID(TYPE a) { return a++; } \ + TYPE post_dec##ID(TYPE a) { return a--; } \ + TYPE deref_pre_inc##ID(TYPE *a) { return ++(*a); } \ + TYPE deref_pre_dec##ID(TYPE *a) { return --(*a); } \ + TYPE deref_post_inc##ID(TYPE *a) { return (*a)++; } \ + TYPE deref_post_dec##ID(TYPE *a) { return (*a)--; } + +#define ALL_OPERATIONS(TYPE, ID) \ + ALL_OPERATIONS_FOR_TYPE(TYPE, ID)\ + ALL_OPERATIONS_FOR_TYPE(signed TYPE, Signed##ID) \ + ALL_OPERATIONS_FOR_TYPE(unsigned TYPE, Unsigned##ID) \ + ALL_OPERATIONS_FOR_TYPE(_Sat TYPE, Sat##ID) \ + ALL_OPERATIONS_FOR_TYPE(_Sat signed TYPE, SatSigned##ID) \ + ALL_OPERATIONS_FOR_TYPE(_Sat unsigned TYPE, SatUnsigned##ID) + +ALL_OPERATIONS(short _Fract, ShortFract); +ALL_OPERATIONS(_Fract, Fract); +ALL_OPERATIONS(long _Fract, LongFract); +ALL_OPERATIONS(short _Accum, ShortAccum); +ALL_OPERATIONS(_Accum, Accum); +ALL_OPERATIONS(long _Accum, LongAccum); Index: lib/CodeGen/CGExprScalar.cpp === --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -2214,39 +2214,51 @@ switch (BT->getKind()) { default: llvm_unreachable("Not a fixed point type!"); + case BuiltinType::SatShortAccum: case BuiltinType::ShortAccum: fbits = BUILTIN_SACCUM_FBIT; break; + case BuiltinType::SatAccum: case BuiltinType::Accum: fbits = BUILTIN_ACCUM_FBIT; break; + case BuiltinType::SatLongAccum: case BuiltinType::LongAccum: fbits = BUILTIN_LACCUM_FBIT; break; + case BuiltinType::SatUShortAccum: case BuiltinType::UShortAccum: fbits = BUILTIN_USACCUM_FBIT; break; + case BuiltinType::SatUAccum: case BuiltinType::UAccum: fbits = BUILTIN_UACCUM_FBIT; break; + case BuiltinType::SatULongAccum:
[PATCH] D46979: [Fixed Point Arithmetic] Test for Conversion Between Valid Builtin Types
leonardchan updated this revision to Diff 147902. leonardchan added a comment. formatting Repository: rC Clang https://reviews.llvm.org/D46979 Files: include/clang/AST/OperationKinds.def lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/Edit/RewriteObjCFoundationAPI.cpp lib/Sema/SemaExpr.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp test/Frontend/fixed_point_all_conversions.c Index: test/Frontend/fixed_point_all_conversions.c === --- /dev/null +++ test/Frontend/fixed_point_all_conversions.c @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -Werror %s + +// Test for conversions between fixed point types and all other valid types. + +// Conversion from one type to another type +#define CONVERT(FROM_TYPE, FROM_ID, TO_TYPE, TO_ID) \ + TO_TYPE FROM_ID##_to_##TO_ID(FROM_TYPE x) { return x; } + +// Conversion between 2 types +#define CONVERT_COMBINATION(TYPE1, ID1, TYPE2, ID2) \ + CONVERT(TYPE1, ID1, TYPE2, ID2) \ + CONVERT(TYPE2, ID2, TYPE1, ID1) + +// Conversion between one type and floating point types +#define CONVERT_BETWEEN_FLOATS(TYPE, ID) \ + CONVERT_COMBINATION(TYPE, ID, float, Float) \ + CONVERT_COMBINATION(TYPE, ID, double, Double) + +// Conversion between one type and an integral type with differant signage +#define CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, INT_TYPE, INT_ID) \ + CONVERT_COMBINATION(TYPE, ID, INT_TYPE, INT_ID) \ + CONVERT_COMBINATION(TYPE, ID, signed INT_TYPE, Signed##INT_ID)\ + CONVERT_COMBINATION(TYPE, ID, unsigned INT_TYPE, Unsigned##INT_ID) + +// Conversion between one type and all integral types +#define CONVERT_BETWEEN_INTEGRALS(TYPE, ID) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, char, Char) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, short, Short) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, int, Int) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, long, Long) \ + CONVERT_BETWEEN_INTEGRALS_WITH_SIGN(TYPE, ID, long long, LongLong) + +// Conversion between one type and a fixed point type with different saturation +#define CONVERT_BETWEEN_FIXED_POINT_WITH_SAT(TYPE, ID, FIXED_TYPE, FIXED_ID) \ + CONVERT_COMBINATION(TYPE, ID, FIXED_TYPE, FIXED_ID)\ + CONVERT_COMBINATION(TYPE, ID, _Sat FIXED_TYPE, Sat##FIXED_ID) + +// Conversion between one type and a fixed point type with different signage +#define CONVERT_BETWEEN_FIXED_POINT_WITH_SIGN(TYPE, ID, FIXED_TYPE, FIXED_ID) \ + CONVERT_BETWEEN_FIXED_POINT_WITH_SAT(TYPE, ID, FIXED_TYPE, FIXED_ID)\ + CONVERT_BETWEEN_FIXED_POINT_WITH_SAT(TYPE, ID, signed FIXED_TYPE, \ + Signed##FIXED_ID) \ + CONVERT_BETWEEN_FIXED_POINT_WITH_SAT(TYPE, ID, unsigned FIXED_TYPE, \ + Unsigned##FIXED_ID) + +// Convert between one type and all fixed point types. +// Add "Type" to the end of the ID to avoid multiple definitions of a function +// if the Type is a fixed point type. +#define CONVERT_BETWEEN_FIXED_POINT(TYPE, ID)\ + CONVERT_BETWEEN_FIXED_POINT_WITH_SIGN(TYPE, ID, _Fract, FractType) \ + CONVERT_BETWEEN_FIXED_POINT_WITH_SIGN(TYPE, ID, _Accum, AccumType) + +// Convert between one type and all other types +#define CONVERT_BETWEEN_ALL_TYPES(TYPE, ID) \ + CONVERT_BETWEEN_FLOATS(TYPE, ID) \ + CONVERT_BETWEEN_INTEGRALS(TYPE, ID) \ + CONVERT_BETWEEN_FIXED_POINT(TYPE, ID) + +#define CONVERT_FIXED_POINT_TYPE_WITH_SAT(TYPE, ID) \ + CONVERT_BETWEEN_ALL_TYPES(TYPE, ID) \ + CONVERT_BETWEEN_ALL_TYPES(_Sat TYPE, Sat##ID) + +#define CONVERT_FIXED_POINT_TYPE(TYPE, ID) \ + CONVERT_FIXED_POINT_TYPE_WITH_SAT(TYPE, ID)\ + CONVERT_FIXED_POINT_TYPE_WITH_SAT(signed TYPE, Signed##ID) \ + CONVERT_FIXED_POINT_TYPE_WITH_SAT(unsigned TYPE, Unsigned##ID) + +CONVERT_FIXED_POINT_TYPE(short _Fract, ShortFract); +CONVERT_FIXED_POINT_TYPE(_Fract, Fract); +CONVERT_FIXED_POINT_TYPE(long _Fract, LongFract); + +CONVERT_FIXED_POINT_TYPE(short _Accum, ShortAccum); +CONVERT_FIXED_POINT_TYPE(_Accum, Accum); +CONVERT_FIXED_POINT_TYPE(long _Accum, LongAccum); Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp === --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -323,6 +323,8 @@ switch (CastE->getCastKind()) { case CK_FixedPointCast: llvm_unreachable("CK_FixedPointCast"); // TODO + case CK_FloatingToFixedPoint: +llvm_unreachable("CK_FloatingToFixedPoint"); case CK_IntegralToFixedPoint: llvm_unreachable( "ExprEngine::VisitCast CK_IntegralToFixedPoint"); // TODO Index:
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 148025. Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -542,6 +548,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +// CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} accum '_Accum' +// CHECK-NEXT: `-VarDecl {{.*}} long_accum 'long _Accum' Index: lib/Serialization/ASTReader.cpp === --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6816,6 +6816,24 @@ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; +case PREDEF_TYPE_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; +case PREDEF_TYPE_ACCUM_ID: + T = Context.AccumTy; + break; +case PREDEF_TYPE_LONG_ACCUM_ID: + T = Context.LongAccumTy; + break; +case PREDEF_TYPE_USHORT_ACCUM_ID:
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan marked 2 inline comments as done. leonardchan added inline comments. Comment at: lib/Index/USRGeneration.cpp:731 + + if (c == '~') { +switch (BT->getKind()) { jakehehrlich wrote: > You can make the 'c' a Twine instead. That will let you inline these in their > respective locations as ` c = "~UA" ` for instance. So Twine also isn't assignable. If I still want to keep the pattern of assigning to a temporary variable, I could instead just make `c` a string. Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46986: [Fixed Point Arithmetic] Validation Test for Fixed Point Binary Operations and Saturated Addition
leonardchan updated this revision to Diff 148116. leonardchan added a comment. - formatting - Running `lli` threw a segfault in the test, though this was probably because it was using whatever hist jit was available to optimize the code instead of just interpreting it. Forcing it just interpret fixes this. Repository: rC Clang https://reviews.llvm.org/D46986 Files: include/clang/AST/Type.h include/clang/Basic/FixedPoint.h.in lib/AST/Type.cpp lib/CodeGen/CGExprScalar.cpp lib/Sema/SemaExpr.cpp test/Frontend/fixed_point_all_builtin_operations.c test/Frontend/fixed_point_builtin_macros.c Index: test/Frontend/fixed_point_builtin_macros.c === --- test/Frontend/fixed_point_builtin_macros.c +++ test/Frontend/fixed_point_builtin_macros.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli +// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli -force-interpreter=true #define assert(b) if (!(b)) { return 1; } Index: test/Frontend/fixed_point_all_builtin_operations.c === --- test/Frontend/fixed_point_all_builtin_operations.c +++ test/Frontend/fixed_point_all_builtin_operations.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -Werror %s +// RUN: %clang_cc1 -Werror -S -emit-llvm %s -o - | lli -force-interpreter=true // Check that we can use all supported binary and unary operations according to // clause 4.1.6 in N1169. @@ -66,3 +66,60 @@ ALL_OPERATIONS(short _Accum, ShortAccum); ALL_OPERATIONS(_Accum, Accum); ALL_OPERATIONS(long _Accum, LongAccum); + +#define ASSERT(x) \ + if (!(x)) return 1; + +#define BINARY_OPS_FOR_TYPE(TYPE, ID, SUFFIX) \ + { \ +TYPE a = 0.5##SUFFIX; \ +TYPE b = 0.25##SUFFIX;\ +ASSERT(add##ID(a, b) == 0.75##SUFFIX);\ +ASSERT(sub##ID(a, b) == 0.25##SUFFIX);\ +ASSERT(mul##ID(a, b) == 0.125##SUFFIX); \ +ASSERT(div##ID(b, a) == 0.5##SUFFIX); \ +ASSERT(shl##ID(b, 1) == a); \ +ASSERT(shr##ID(a, 1) == b); \ +ASSERT(lt##ID(b, a)); \ +ASSERT(le##ID(b, a)); \ +ASSERT(gt##ID(a, b)); \ +ASSERT(ge##ID(a, b)); \ +ASSERT(eq##ID(a, b) == 0);\ +ASSERT(ne##ID(a, b)); \ +ASSERT(augmented_add##ID(a, b) == 0.75##SUFFIX); \ +ASSERT(augmented_sub##ID(a, b) == 0.25##SUFFIX); \ +ASSERT(augmented_mul##ID(a, b) == 0.125##SUFFIX); \ +ASSERT(augmented_div##ID(b, a) == 0.5##SUFFIX); \ +ASSERT(augmented_shl##ID(b, 1) == a); \ +ASSERT(augmented_shr##ID(a, 1) == b); \ + } + +#define BINARY_OPS(TYPE, ID, SUFFIX)\ + BINARY_OPS_FOR_TYPE(TYPE, ID, SUFFIX);\ + BINARY_OPS_FOR_TYPE(signed TYPE, Signed##ID, SUFFIX); \ + BINARY_OPS_FOR_TYPE(unsigned TYPE, Unsigned##ID, u##SUFFIX); \ + BINARY_OPS_FOR_TYPE(_Sat TYPE, Sat##ID, SUFFIX); \ + BINARY_OPS_FOR_TYPE(_Sat signed TYPE, SatSigned##ID, SUFFIX); \ + BINARY_OPS_FOR_TYPE(_Sat unsigned TYPE, SatUnsigned##ID, u##SUFFIX); + +#define FRACT_SAT_BINARY_OPS(TYPE, ID, SUFFIX) \ + {\ +TYPE a = 0.7##SUFFIX; \ +TYPE b = 0.9##SUFFIX; \ +ASSERT(add##ID(a, b) == 1.0##SUFFIX); \ + } + +int main() { + BINARY_OPS(short _Fract, ShortFract, hr); + BINARY_OPS(_Fract, Fract, r); + BINARY_OPS(long _Fract, LongFract, lr); + BINARY_OPS(short _Accum, ShortAccum, hk); + BINARY_OPS(_Accum, Accum, k); + BINARY_OPS(long _Accum, LongAccum, lk); + + FRACT_SAT_BINARY_OPS(_Sat short _Fract, SatShortFract, hr); + FRACT_SAT_BINARY_OPS(_Sat _Fract, SatFract, r); + FRACT_SAT_BINARY_OPS(_Sat long _Fract, SatLongFract, lr); + + return 0; +} Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -1258,8 +1258,12 @@ return FixedPointTy; } -/// \brief Handle arithmethic conversion with fixed point types. Helper -/// function of UsualArithmeticConversions(). +/// \brief Handle arithmethic conversion with fixed point types. The usual +/// arithmetic conversions do not apply to fixed point type conversions between +/// integers or other fixed point types due to potential loss of precision. +/// For this case of fixed point types, the resulting type in a binary operation +/// does not need to be exactly one of the 2 operand types. +/// Implemented according to Clause 6.3.1.8 of ISO/IEC JTC1 SC22 WG14 N1169. static QualType handleFixedPointConversion(Sema &S, ExprResult &LHS,
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 148117. leonardchan marked an inline comment as done. Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -542,6 +548,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +// CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} accum '_Accum' +// CHECK-NEXT: `-VarDecl {{.*}} long_accum 'long _Accum' Index: lib/Serialization/ASTReader.cpp === --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6816,6 +6816,24 @@ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; +case PREDEF_TYPE_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; +case PREDEF_TYPE_ACCUM_ID: + T = Context.AccumTy; + break; +case PREDEF_TYPE_LONG_ACCUM_ID: + T = Context.LongAccumTy; +
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 148121. Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -542,6 +548,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +// CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} accum '_Accum' +// CHECK-NEXT: `-VarDecl {{.*}} long_accum 'long _Accum' Index: lib/Serialization/ASTReader.cpp === --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6816,6 +6816,24 @@ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; +case PREDEF_TYPE_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; +case PREDEF_TYPE_ACCUM_ID: + T = Context.AccumTy; + break; +case PREDEF_TYPE_LONG_ACCUM_ID: + T = Context.LongAccumTy; + break; +case PREDEF_TYPE_USHORT_ACCUM_ID:
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 148148. leonardchan added a comment. pulled changes from source tree Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/accum.c test/Frontend/accum_errors.c test/Frontend/accum_errors.cpp tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -546,6 +552,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/accum_errors.cpp === --- /dev/null +++ test/Frontend/accum_errors.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -x c++ %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{Fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{Fixed point types are only allowed in C}} +signed long _Accum s_long_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned _Accum u_accum; // expected-error{{Fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{Fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{Fixed point types are only allowed in C}} +_Accum accum; // expected-error{{Fixed point types are only allowed in C}} +long _Accum long_accum; // expected-error{{Fixed point types are only allowed in C}} Index: test/Frontend/accum_errors.c === --- /dev/null +++ test/Frontend/accum_errors.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s + +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} Index: test/Frontend/accum.c === --- /dev/null +++ test/Frontend/accum.c @@ -0,0 +1,26 @@ +// RUN: %clang -cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +/* Various contexts where type _Accum can appear. */ + +// Primary fixed point types +signed short _Accum s_short_accum; +signed _Accum s_accum; +signed long _Accum s_long_accum; +unsigned short _Accum u_short_accum; +unsigned _Accum u_accum; +unsigned long _Accum u_long_accum; + +// Aliased fixed point types +short _Accum short_accum; +_Accum accum; +long _Accum long_accum; + +// CHECK: |-VarDecl {{.*}} s_short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_accum '_Accum' +// CHECK-NEXT: |-VarDecl {{.*}} s_long_accum 'long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_short_accum 'unsigned short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_accum 'unsigned _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} u_long_accum 'unsigned long _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} short_accum 'short _Accum' +// CHECK-NEXT: |-VarDecl {{.*}} accum '_Accum' +// CHECK-NEXT: `-VarDecl {{.*}} long_accum 'long _Accum' Index: lib/Serialization/ASTReader.cpp === --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6818,6 +6818,24 @@ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; +case PREDEF_TYPE_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; +case PREDEF_TYPE_ACCUM_ID: + T = Context.AccumTy; + break; +case PREDEF_TYPE_LONG_ACCUM_ID: + T = Context.Lon
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan added a subscriber: sammccall. leonardchan added inline comments. Comment at: include/clang/Basic/DiagnosticCommonKinds.td:172 +def err_fixed_point_only_allowed_in_c : Error< + "Fixed point types are only allowed in C">; rsmith wrote: > Diagnostics should not be capitalized. Also, we generally allow conforming C > extensions to be used in other languages unless there is a really good reason > not to. We decided not to allow fixed point types in other languages because there is no specification provided in N1169 for addressing some features in other languages. Using C++ as an example, N1169 does not provide recommended characters when name mangling so we do not allow this in C++. Comment at: lib/AST/ItaniumMangle.cpp:2552 + case BuiltinType::ULongAccum: +llvm_unreachable("Fixed point types are disabled for c++"); case BuiltinType::Half: rsmith wrote: > Please check what GCC uses to mangle these, and follow suit; if GCC doesn't > have a mangling, you can use a vendor mangling (`u6_Accum`) or produce an > error for now, but please open an issue at > https://github.com/itanium-cxx-abi/cxx-abi/ to pick a real mangling. It seems that GCC uses the characters for each fixed point type's corresponding integral type (https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/mangle.c). Will follow up on this if we end up enabling fixed point types for C++. Comment at: lib/CodeGen/CGDebugInfo.cpp:678-681 + case BuiltinType::UShortAccum: + case BuiltinType::UAccum: + case BuiltinType::ULongAccum: Encoding = llvm::dwarf::DW_ATE_unsigned; rsmith wrote: > @echristo @dblaikie Is this appropriate? My bad, this should be changed to `DW_ATE_signed_fixed` and `DW_ATE_unsigned_fixed` Comment at: lib/Index/USRGeneration.cpp:691 +case BuiltinType::ULongAccum: + llvm_unreachable("No USR name mangling for fixed point types."); case BuiltinType::Float16: rsmith wrote: > leonardchan wrote: > > phosek wrote: > > > We need some solution for fixed point types. > > Added character ~ to indicate fixed point type followed by string detailing > > the type. I have not added a test to it because logically, I do not think > > we will ever reach that point. This logic is implemented in the VisitType > > method, which mostly gets called by visitors to c++ nodes like > > VisitTemplateParameterList, but we have disabled the use of fixed point > > types in c++. VisitType does get called in VisitFunctionDecl but the > > function exits early since we are not reading c++ (line > > lib/Index/USRGeneration.cpp:238). > @rjmccall Is this an acceptable USR encoding? (Is our USR encoding scheme > documented anywhere?) I chatted with @sammccall about this who said it was ok to add these types if no one opposed this. I posted this on cfe-dev also and it seemed that no one spoke up about it, so I thought this was ok. I also couldn't find any standard or documentation about reserving characters for USR. It doesn't seem that USR is also parsed in any way, so I don't think I'm breaking anything (running ninja check-all passes). And unless we also do enable this for C++, this code actually may not be run since this method will not be visited if limited to C. Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan added inline comments. Comment at: include/clang/Basic/DiagnosticCommonKinds.td:172 +def err_fixed_point_only_allowed_in_c : Error< + "Fixed point types are only allowed in C">; leonardchan wrote: > rsmith wrote: > > Diagnostics should not be capitalized. Also, we generally allow conforming > > C extensions to be used in other languages unless there is a really good > > reason not to. > We decided not to allow fixed point types in other languages because there is > no specification provided in N1169 for addressing some features in other > languages. Using C++ as an example, N1169 does not provide recommended > characters when name mangling so we do not allow this in C++. Actually, scratch that. We will be enabling it since GCC does. Will update this and other relevant C++ related code appropriately. Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan added inline comments. Comment at: include/clang/Basic/DiagnosticCommonKinds.td:172 +def err_fixed_point_only_allowed_in_c : Error< + "Fixed point types are only allowed in C">; leonardchan wrote: > leonardchan wrote: > > rsmith wrote: > > > Diagnostics should not be capitalized. Also, we generally allow > > > conforming C extensions to be used in other languages unless there is a > > > really good reason not to. > > We decided not to allow fixed point types in other languages because there > > is no specification provided in N1169 for addressing some features in other > > languages. Using C++ as an example, N1169 does not provide recommended > > characters when name mangling so we do not allow this in C++. > Actually, scratch that. We will be enabling it since GCC does. Will update > this and other relevant C++ related code appropriately. Actually, the main thing that was preventing us from allowing this in C++ was no standardized characters for name mangling. GCC seems to use the same characters as some integral types (`short _Accum` uses `s`, `_Accum` uses `i`, ...) but this would mean that a function that takes a `short _Accum` as a sole argument would also be mangled the same as a similarly named function that takes a `short`. Would copying GCC take priority over not having characters specific for these types? This standard also proposes 24 different types, of which only 6 are included in this patch. Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan added a comment. After further discussion, we think the best approach for now would be only supporting fixed point types in C, then go back and support C++ once there is a standardized way for mangling the fixed point types under itanium. Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 148445. leonardchan added a comment. - Reverted changes involving name mangling since we will only support c++ for now. Will concurrently raise an issue on https://github.com/itanium-cxx-abi/cxx-abi/ to get characters for name mangling. - Added a flag that needs to be provided to enable usage of fixed point types. Not including this flag and using fixed point types throws an error. Currently, this patch allows for these types to be used in all versions of C, but this can be narrowed down to specific versions of C. - An error is thrown when using fixed point types in C++. - Fixed point types are ignored during USRGeneration since the type only gets mangled in C++. - Fixed point types their own width and alignment accessors/variables in TargetInfo. - Updated debug info to use `DW_ATE_signed_fixed` and `DW_ATE_unsigned_fixed`. - Added tests mixing _Accum with other type specifiers Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/LangOptions.def include/clang/Basic/Specifiers.h include/clang/Basic/TargetInfo.h include/clang/Basic/TokenKinds.def include/clang/Driver/Options.td include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/Basic/TargetInfo.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_errors.cpp test/Frontend/fixed_point_not_enabled.c tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -546,6 +552,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/fixed_point_not_enabled.c === --- /dev/null +++ test/Frontend/fixed_point_not_enabled.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -x c -verify %s + +// Primary fixed point types +signed short _Accum s_short_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +signed _Accum s_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +signed long _Accum s_long_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned short _Accum u_short_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned _Accum u_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned long _Accum u_long_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} + +// Aliased fixed point types +short _Accum short_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +_Accum accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} + // expected-warning@-1{{type specifier missing, defaults to 'int'}} +long _Accum long_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} Index: test/Frontend/fixed_point_errors.cpp === --- /dev/null +++ test/Frontend/fixed_point_errors.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -x c++ -enable-fixed-point %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{fixed point types are only allowed in C}} +signed long _Accum s_long_accum;// expected-e
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan marked 6 inline comments as done. leonardchan added inline comments. Comment at: lib/CodeGen/ItaniumCXXABI.cpp:2684 // Types added here must also be added to EmitFundamentalRTTIDescriptors. switch (Ty->getKind()) { rsmith wrote: > Note this comment :) Returned false for these types now. Not sure if these types should also be added to EmitFundamentalRTTIDescriptors since the OCL types do not appear under there. Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 148452. Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/LangOptions.def include/clang/Basic/Specifiers.h include/clang/Basic/TargetInfo.h include/clang/Basic/TokenKinds.def include/clang/Driver/Options.td include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/Basic/TargetInfo.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_errors.cpp test/Frontend/fixed_point_not_enabled.c tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -546,6 +552,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/fixed_point_not_enabled.c === --- /dev/null +++ test/Frontend/fixed_point_not_enabled.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -x c -verify %s + +// Primary fixed point types +signed short _Accum s_short_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +signed _Accum s_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +signed long _Accum s_long_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned short _Accum u_short_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned _Accum u_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned long _Accum u_long_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} + +// Aliased fixed point types +short _Accum short_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +_Accum accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} + // expected-warning@-1{{type specifier missing, defaults to 'int'}} +long _Accum long_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} Index: test/Frontend/fixed_point_errors.cpp === --- /dev/null +++ test/Frontend/fixed_point_errors.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -x c++ -enable-fixed-point %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{fixed point types are only allowed in C}} +signed long _Accum s_long_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned _Accum u_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{fixed point types are only allowed in C}} +_Accum accum; // expected-error{{fixed point types are only allowed in C}} +// expected-error@-1{{C++ requires a type specifier for all declarations}} +long _Accum long_accum; // expected-error{{fixed point types are only allowed in C}} Index: test/Frontend/fixed_point_errors.c === ---
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 148481. leonardchan marked 2 inline comments as done. leonardchan added a comment. - Added test case for `_Bool _Accum` - Getters for the `_Accum` bit widths return values for their corresponding integral types (ie. `sizeof(short _Accum) == sizeof(short)`). The only case where this may not happen is if the target architecture uses 16 bits for an int. N1169 requires that a `signed/unsigned _Accum` hold at least 15 fractional bits and 4 integral bits. To be able to fit these bits, the size is upgraded to that of a long which is guaranteed to be large enough to hold them. Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/LangOptions.def include/clang/Basic/Specifiers.h include/clang/Basic/TargetInfo.h include/clang/Basic/TokenKinds.def include/clang/Driver/Options.td include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_bit_widths.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_errors.cpp test/Frontend/fixed_point_not_enabled.c tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -546,6 +552,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/fixed_point_not_enabled.c === --- /dev/null +++ test/Frontend/fixed_point_not_enabled.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -x c -verify %s + +// Primary fixed point types +signed short _Accum s_short_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +signed _Accum s_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +signed long _Accum s_long_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned short _Accum u_short_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned _Accum u_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned long _Accum u_long_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} + +// Aliased fixed point types +short _Accum short_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +_Accum accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} + // expected-warning@-1{{type specifier missing, defaults to 'int'}} +long _Accum long_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} Index: test/Frontend/fixed_point_errors.cpp === --- /dev/null +++ test/Frontend/fixed_point_errors.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -x c++ -enable-fixed-point %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{fixed point types are only allowed in C}} +signed long _Accum s_long_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned _Accum u_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expecte
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan added a comment. In https://reviews.llvm.org/D46084#374, @jfb wrote: > Can you also add a test for `_Bool _Accum`. > > Also, `-enable-fixed-point -x c++` failing. . Done. Also the failing c++ case is under `test/Frontend/fixed_point_errors.cpp` Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 148506. leonardchan added a comment. Re-added individual getters/members for _Accum types Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/LangOptions.def include/clang/Basic/Specifiers.h include/clang/Basic/TargetInfo.h include/clang/Basic/TokenKinds.def include/clang/Driver/Options.td include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/Basic/TargetInfo.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_bit_widths.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_errors.cpp test/Frontend/fixed_point_not_enabled.c tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -546,6 +552,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/fixed_point_not_enabled.c === --- /dev/null +++ test/Frontend/fixed_point_not_enabled.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -x c -verify %s + +// Primary fixed point types +signed short _Accum s_short_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +signed _Accum s_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +signed long _Accum s_long_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned short _Accum u_short_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned _Accum u_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +unsigned long _Accum u_long_accum;// expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} + +// Aliased fixed point types +short _Accum short_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} +_Accum accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} + // expected-warning@-1{{type specifier missing, defaults to 'int'}} +long _Accum long_accum; // expected-error{{compile with '-enable-fixed-point' to enable fixed point types}} Index: test/Frontend/fixed_point_errors.cpp === --- /dev/null +++ test/Frontend/fixed_point_errors.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -x c++ -enable-fixed-point %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{fixed point types are only allowed in C}} +signed long _Accum s_long_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned _Accum u_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{fixed point types are only allowed in C}} +_Accum accum; // expected-error{{fixed point types are only allowed in C}} +// expected-error@-1{{C++ requires a type specifier for all declarations}} +long _Accum long_accum; // expected-error{{fixed point types are only allo
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan added inline comments. Comment at: include/clang/Basic/TargetInfo.h:382 +// enough bits to fit the minumum. +if (getIntWidth() < MinSignedAccumDataBits) + return getLongWidth(); ebevhan wrote: > I'm not sure I agree with this interpretation. It's simply not correct to > consider 'short' the 'underlying type' of 'short _Accum', 'int' the > 'underlying type' of '_Accum', etc. They are wholly independent and should > have separate settings altogether. > > Asserting/ensuring that a target has set an invalid width for its types > should be done separately. This currently feels a bit like the TargetInfo is > guessing. > > (For the record, the reason I'm requesting this change is because this > implementation does not work for us downstream.) You're right. They should be different types. I was stuck in the mindset that `short _Accum` should be tied to `short`, `_Accum` be tied to `int`, etc. Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan updated this revision to Diff 148637. leonardchan added a comment. Changed flag names Repository: rC Clang https://reviews.llvm.org/D46084 Files: include/clang-c/Index.h include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/LangOptions.def include/clang/Basic/Specifiers.h include/clang/Basic/TargetInfo.h include/clang/Basic/TokenKinds.def include/clang/Driver/Options.td include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/Basic/TargetInfo.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_bit_widths.c test/Frontend/fixed_point_errors.c test/Frontend/fixed_point_errors.cpp test/Frontend/fixed_point_not_enabled.c tools/libclang/CXType.cpp Index: tools/libclang/CXType.cpp === --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -53,6 +53,12 @@ BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); +BTCASE(ShortAccum); +BTCASE(Accum); +BTCASE(LongAccum); +BTCASE(UShortAccum); +BTCASE(UAccum); +BTCASE(ULongAccum); BTCASE(Float16); BTCASE(Float128); BTCASE(NullPtr); @@ -546,6 +552,12 @@ TKIND(Float); TKIND(Double); TKIND(LongDouble); +TKIND(ShortAccum); +TKIND(Accum); +TKIND(LongAccum); +TKIND(UShortAccum); +TKIND(UAccum); +TKIND(ULongAccum); TKIND(Float16); TKIND(Float128); TKIND(NullPtr); Index: test/Frontend/fixed_point_not_enabled.c === --- /dev/null +++ test/Frontend/fixed_point_not_enabled.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -x c -verify %s +// RUN: %clang_cc1 -x c -fno-fixed-point -verify %s + +// Primary fixed point types +signed short _Accum s_short_accum;// expected-error{{compile with '-ffixed-point' to enable fixed point types}} +signed _Accum s_accum;// expected-error{{compile with '-ffixed-point' to enable fixed point types}} +signed long _Accum s_long_accum; // expected-error{{compile with '-ffixed-point' to enable fixed point types}} +unsigned short _Accum u_short_accum; // expected-error{{compile with '-ffixed-point' to enable fixed point types}} +unsigned _Accum u_accum; // expected-error{{compile with '-ffixed-point' to enable fixed point types}} +unsigned long _Accum u_long_accum;// expected-error{{compile with '-ffixed-point' to enable fixed point types}} + +// Aliased fixed point types +short _Accum short_accum; // expected-error{{compile with '-ffixed-point' to enable fixed point types}} +_Accum accum; // expected-error{{compile with '-ffixed-point' to enable fixed point types}} + // expected-warning@-1{{type specifier missing, defaults to 'int'}} +long _Accum long_accum; // expected-error{{compile with '-ffixed-point' to enable fixed point types}} Index: test/Frontend/fixed_point_errors.cpp === --- /dev/null +++ test/Frontend/fixed_point_errors.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -x c++ -ffixed-point %s -verify + +// Name namgling is not provided for fixed point types in c++ + +signed short _Accum s_short_accum; // expected-error{{fixed point types are only allowed in C}} +signed _Accum s_accum; // expected-error{{fixed point types are only allowed in C}} +signed long _Accum s_long_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned short _Accum u_short_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned _Accum u_accum;// expected-error{{fixed point types are only allowed in C}} +unsigned long _Accum u_long_accum; // expected-error{{fixed point types are only allowed in C}} + +short _Accum short_accum; // expected-error{{fixed point types are only allowed in C}} +_Accum accum; // expected-error{{fixed point types are only allowed in C}} +// expected-error@-1{{C++ requires a type specifier for all declarations}} +long _Accum long_accum; // expected-error{{fixed point types are only allowed in C}} Index: test/Frontend/fixed_poi
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan marked 2 inline comments as done. leonardchan added inline comments. Comment at: include/clang/Driver/Options.td:882 +def enable_fixed_point : Flag<["-", "--"], "enable-fixed-point">, Group, + Flags<[CC1Option]>, HelpText<"Enable fixed point types">; ebevhan wrote: > Shouldn't this be an `-f` flag, like `-ffixed-point`? I'm not for or against > either, just wondering what anyone else thinks. Makes sense since this flag is target independent. Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46911: [Fixed Point Arithmetic] Addition of the remaining fixed point types and their saturated equivalents
leonardchan updated this revision to Diff 148918. leonardchan marked 4 inline comments as done. Repository: rC Clang https://reviews.llvm.org/D46911 Files: include/clang/AST/ASTContext.h include/clang/AST/BuiltinTypes.def include/clang/AST/Type.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TargetInfo.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTContext.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/MicrosoftMangle.cpp lib/AST/NSAPI.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/PrintfFormatString.cpp lib/Basic/TargetInfo.cpp lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/Index/USRGeneration.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReader.cpp test/Frontend/fixed_point.c test/Frontend/fixed_point_bit_widths.c test/Frontend/fixed_point_errors.c Index: test/Frontend/fixed_point_errors.c === --- test/Frontend/fixed_point_errors.c +++ test/Frontend/fixed_point_errors.c @@ -5,6 +5,14 @@ long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} +unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} + +_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat unsigned long long _Accum sat_u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat long long _Fract sat_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +_Sat unsigned long long _Fract sat_u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} + /* Although _Complex types work with floating point numbers, the extension * provides no info for complex fixed point types. */ @@ -19,9 +27,53 @@ _Complex _Accum cmplx_s_accum; // expected-error{{'_Complex _Accum' is invalid}} _Complex long _Accum cmplx_s_long_accum;// expected-error{{'_Complex _Accum' is invalid}} +_Complex signed short _Fract cmplx_s_short_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex signed _Fract cmplx_s_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex signed long _Fract cmplx_s_long_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex unsigned short _Fract cmplx_u_short_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex unsigned _Fract cmplx_u_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex unsigned long _Fract cmplx_u_long_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex short _Fract cmplx_s_short_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex _Fract cmplx_s_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex long _Fract cmplx_s_long_fract;// expected-error{{'_Complex _Fract' is invalid}} + +_Complex _Sat signed short _Accum cmplx_sat_s_short_accum; // expected-error{{'_Complex _Accum' is invalid}} +_Complex _Sat signed _Accum cmplx_sat_s_accum; // expected-error{{'_Complex _Accum' is invalid}} +_Complex _Sat signed long _Accum cmplx_sat_s_long_accum; // expected-error{{'_Complex _Accum' is invalid}} +_Complex _Sat unsigned short _Accum cmplx_sat_u_short_accum; // expected-error{{'_Complex _Accum' is invalid}} +_Complex _Sat unsigned _Accum cmplx_sat_u_accum; // expected-error{{'_Complex _Accum' is invalid}} +_Complex _Sat unsigned long _Accum cmplx_sat_u_long_accum; // expected-error{{'_Complex _Accum' is invalid}} +_Complex _Sat short _Accum cmplx_sat_s_short_accum; // expected-error{{'_Complex _Accum' is invalid}} +_Complex _Sat _Accum cmplx_sat_s_accum; // expected-error{{'_Complex _Accum' is invalid}} +_Complex _Sat long _Accum cmplx_sat_s_long_accum;// expected-error{{'_Complex _Accum' is invalid}} + +_Complex signed short _Fract cmplx_sat_s_short_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex signed _Fract cmplx_sat_s_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex signed long _Fract cmplx_sat_s_long_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex unsigned short _Fract cmplx_sat_u_short_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Complex unsigned _Fract cmplx_sat_u_fract; // expected-error{{'_Complex _Fract' is invalid}} +_Comp
[PATCH] D46911: [Fixed Point Arithmetic] Addition of the remaining fixed point types and their saturated equivalents
leonardchan added inline comments. Comment at: lib/Sema/SemaType.cpp:1430 } else { - switch (DS.getTypeSpecWidth()) { -case DeclSpec::TSW_short: - Result = Context.UnsignedShortAccumTy; - break; -case DeclSpec::TSW_unspecified: - Result = Context.UnsignedAccumTy; - break; -case DeclSpec::TSW_long: - Result = Context.UnsignedLongAccumTy; - break; -case DeclSpec::TSW_longlong: - // TODO: Replace with diag - llvm_unreachable("Unable to specify long long as _Accum width"); - break; + if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { +switch (DS.getTypeSpecWidth()) { ebevhan wrote: > You should probably use the 'getCorrespondingSaturatingType' function instead > of disambiguating the whole thing here again. Also used getCorrespondingSignedType() for the signage Repository: rC Clang https://reviews.llvm.org/D46911 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D46084: [Fixed Point Arithmetic] Addition of the Fixed Point _Accum type
leonardchan added a comment. Hi all, I think I've addressed all comments on this patch and will be committing tomorrow morning unless anyone has any more comments they'd like to bring up. Repository: rC Clang https://reviews.llvm.org/D46084 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51229: [Sema/Attribute] Make types declared with address_space an AttributedType
leonardchan created this revision. leonardchan added reviewers: rjmccall, rsmith, phosek, mcgrathr, ebevhan, theraven. leonardchan added a project: clang. Currently an address_space is stored in a qualifier. This makes any type declared with an address_space attribute in the form `__attribute__((address_space(1))) int 1;` be wrapped in an AttributedType. This is for a later patch where if `address_space` is declared in a macro, any diagnostics that would normally print the address space will instead dump the macro name. This will require saving any macro information in the AttributedType. Repository: rC Clang https://reviews.llvm.org/D51229 Files: include/clang/Basic/Attr.td lib/AST/TypePrinter.cpp lib/Sema/SemaType.cpp Index: lib/Sema/SemaType.cpp === --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -7281,10 +7281,21 @@ case ParsedAttr::AT_OpenCLLocalAddressSpace: case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: -case ParsedAttr::AT_AddressSpace: +case ParsedAttr::AT_AddressSpace: { HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); + + if (attr.getKind() == ParsedAttr::AT_AddressSpace && + !type->getAs()) { +ASTContext &Ctx = state.getSema().Context; +auto *ASAttr = ::new (Ctx) AddressSpaceAttr( +attr.getRange(), Ctx, attr.getAttributeSpellingListIndex(), +static_cast(type.getQualifiers().getAddressSpace())); +type = state.getAttributedType(ASAttr, type, type); + } + attr.setUsedAsTypeAttr(); break; +} OBJC_POINTER_TYPE_ATTRS_CASELIST: if (!handleObjCPointerTypeAttr(state, attr, type)) distributeObjCPointerTypeAttr(state, attr, type); Index: lib/AST/TypePrinter.cpp === --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1427,6 +1427,9 @@ return; } + if (T->getAttrKind() == attr::AddressSpace) +return; + OS << " __attribute__(("; switch (T->getAttrKind()) { #define TYPE_ATTR(NAME) @@ -1494,6 +1497,9 @@ case attr::PreserveAll: OS << "preserve_all"; break; + + case attr::AddressSpace: +llvm_unreachable("Printing of address_space is handled by the qualifier"); } OS << "))"; } Index: include/clang/Basic/Attr.td === --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -564,8 +564,6 @@ let Spellings = [Clang<"address_space">]; let Args = [IntArgument<"AddressSpace">]; let Documentation = [Undocumented]; - // Represented as a qualifier or DependentAddressSpaceType instead. - let ASTNode = 0; } def Alias : Attr { Index: lib/Sema/SemaType.cpp === --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -7281,10 +7281,21 @@ case ParsedAttr::AT_OpenCLLocalAddressSpace: case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: -case ParsedAttr::AT_AddressSpace: +case ParsedAttr::AT_AddressSpace: { HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); + + if (attr.getKind() == ParsedAttr::AT_AddressSpace && + !type->getAs()) { +ASTContext &Ctx = state.getSema().Context; +auto *ASAttr = ::new (Ctx) AddressSpaceAttr( +attr.getRange(), Ctx, attr.getAttributeSpellingListIndex(), +static_cast(type.getQualifiers().getAddressSpace())); +type = state.getAttributedType(ASAttr, type, type); + } + attr.setUsedAsTypeAttr(); break; +} OBJC_POINTER_TYPE_ATTRS_CASELIST: if (!handleObjCPointerTypeAttr(state, attr, type)) distributeObjCPointerTypeAttr(state, attr, type); Index: lib/AST/TypePrinter.cpp === --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1427,6 +1427,9 @@ return; } + if (T->getAttrKind() == attr::AddressSpace) +return; + OS << " __attribute__(("; switch (T->getAttrKind()) { #define TYPE_ATTR(NAME) @@ -1494,6 +1497,9 @@ case attr::PreserveAll: OS << "preserve_all"; break; + + case attr::AddressSpace: +llvm_unreachable("Printing of address_space is handled by the qualifier"); } OS << "))"; } Index: include/clang/Basic/Attr.td === --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -564,8 +564,6 @@ let Spellings = [Clang<"address_space">]; let Args = [IntArgument<"AddressSpace">]; let Documentation = [Undocumented]; - // Represented as a qualifier or DependentAddressSpaceType instead. - let ASTNode = 0; } def Alias : Attr { ___ cfe-commits
[PATCH] D49511: [Sema/Attribute] Check for noderef attribute
leonardchan added a comment. @rsmith ping Repository: rC Clang https://reviews.llvm.org/D49511 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51229: [Sema/Attribute] Make types declared with address_space an AttributedType
leonardchan updated this revision to Diff 162487. leonardchan marked 3 inline comments as done. Repository: rC Clang https://reviews.llvm.org/D51229 Files: include/clang/Basic/Attr.td lib/AST/TypePrinter.cpp lib/Sema/SemaType.cpp Index: lib/Sema/SemaType.cpp === --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5767,7 +5767,10 @@ /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, -const ParsedAttr &Attr, Sema &S) { +const ParsedAttr &Attr, +TypeProcessingState &State) { + Sema &S = State.getSema(); + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be // qualified by an address-space qualifier." if (Type->isFunctionType()) { @@ -5809,10 +5812,18 @@ // the type. QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); -if (!T.isNull()) +if (!T.isNull()) { + if (!T->getAs()) { +ASTContext &Ctx = S.Context; +auto *ASAttr = ::new (Ctx) AddressSpaceAttr( +Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), +static_cast(T.getQualifiers().getAddressSpace())); +T = State.getAttributedType(ASAttr, T, T); + } Type = T; -else +} else { Attr.setInvalid(); +} } else { // The keyword-based type attributes imply which address space to use. switch (Attr.getKind()) { @@ -7282,7 +7293,7 @@ case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: case ParsedAttr::AT_AddressSpace: - HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); + HandleAddressSpaceTypeAttribute(type, attr, state); attr.setUsedAsTypeAttr(); break; OBJC_POINTER_TYPE_ATTRS_CASELIST: Index: lib/AST/TypePrinter.cpp === --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1427,6 +1427,12 @@ return; } + // The printing of the address_space attribute is handled by the qualifier + // since it is still stored in the qualifier. Return early to prevent printing + // this twice. + if (T->getAttrKind() == attr::AddressSpace) +return; + OS << " __attribute__(("; switch (T->getAttrKind()) { #define TYPE_ATTR(NAME) @@ -1456,6 +1462,7 @@ case attr::Ptr64: case attr::SPtr: case attr::UPtr: + case attr::AddressSpace: llvm_unreachable("This attribute should have been handled already"); case attr::NSReturnsRetained: Index: include/clang/Basic/Attr.td === --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -564,8 +564,6 @@ let Spellings = [Clang<"address_space">]; let Args = [IntArgument<"AddressSpace">]; let Documentation = [Undocumented]; - // Represented as a qualifier or DependentAddressSpaceType instead. - let ASTNode = 0; } def Alias : Attr { Index: lib/Sema/SemaType.cpp === --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5767,7 +5767,10 @@ /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, -const ParsedAttr &Attr, Sema &S) { +const ParsedAttr &Attr, +TypeProcessingState &State) { + Sema &S = State.getSema(); + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be // qualified by an address-space qualifier." if (Type->isFunctionType()) { @@ -5809,10 +5812,18 @@ // the type. QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); -if (!T.isNull()) +if (!T.isNull()) { + if (!T->getAs()) { +ASTContext &Ctx = S.Context; +auto *ASAttr = ::new (Ctx) AddressSpaceAttr( +Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), +static_cast(T.getQualifiers().getAddressSpace())); +T = State.getAttributedType(ASAttr, T, T); + } Type = T; -else +} else { Attr.setInvalid(); +} } else { // The keyword-based type attributes imply which address space to use. switch (Attr.getKind()) { @@ -7282,7 +7293,7 @@ case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: case ParsedAttr::AT_AddressSpace: - HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); + HandleAddressSpaceTypeAttribute(type, attr, state); attr.setUsedAsTypeAttr(); break;
[PATCH] D51229: [Sema/Attribute] Make types declared with address_space an AttributedType
leonardchan updated this revision to Diff 162515. leonardchan marked an inline comment as done. Repository: rC Clang https://reviews.llvm.org/D51229 Files: include/clang/Basic/Attr.td lib/AST/TypePrinter.cpp lib/Sema/SemaType.cpp Index: lib/Sema/SemaType.cpp === --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5615,6 +5615,12 @@ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); } +while (DependentAddressSpaceTypeLoc TL = + CurrTL.getAs()) { + fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs()); + CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc(); +} + // FIXME: Ordering here? while (AdjustedTypeLoc TL = CurrTL.getAs()) CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); @@ -5767,7 +5773,10 @@ /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, -const ParsedAttr &Attr, Sema &S) { +const ParsedAttr &Attr, +TypeProcessingState &State) { + Sema &S = State.getSema(); + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be // qualified by an address-space qualifier." if (Type->isFunctionType()) { @@ -5809,10 +5818,15 @@ // the type. QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); -if (!T.isNull()) - Type = T; -else +if (!T.isNull()) { + ASTContext &Ctx = S.Context; + auto *ASAttr = ::new (Ctx) AddressSpaceAttr( + Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), + static_cast(T.getQualifiers().getAddressSpace())); + Type = State.getAttributedType(ASAttr, T, T); +} else { Attr.setInvalid(); +} } else { // The keyword-based type attributes imply which address space to use. switch (Attr.getKind()) { @@ -7282,7 +7296,7 @@ case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: case ParsedAttr::AT_AddressSpace: - HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); + HandleAddressSpaceTypeAttribute(type, attr, state); attr.setUsedAsTypeAttr(); break; OBJC_POINTER_TYPE_ATTRS_CASELIST: Index: lib/AST/TypePrinter.cpp === --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1427,6 +1427,12 @@ return; } + // The printing of the address_space attribute is handled by the qualifier + // since it is still stored in the qualifier. Return early to prevent printing + // this twice. + if (T->getAttrKind() == attr::AddressSpace) +return; + OS << " __attribute__(("; switch (T->getAttrKind()) { #define TYPE_ATTR(NAME) @@ -1456,6 +1462,7 @@ case attr::Ptr64: case attr::SPtr: case attr::UPtr: + case attr::AddressSpace: llvm_unreachable("This attribute should have been handled already"); case attr::NSReturnsRetained: Index: include/clang/Basic/Attr.td === --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -564,8 +564,6 @@ let Spellings = [Clang<"address_space">]; let Args = [IntArgument<"AddressSpace">]; let Documentation = [Undocumented]; - // Represented as a qualifier or DependentAddressSpaceType instead. - let ASTNode = 0; } def Alias : Attr { Index: lib/Sema/SemaType.cpp === --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5615,6 +5615,12 @@ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); } +while (DependentAddressSpaceTypeLoc TL = + CurrTL.getAs()) { + fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs()); + CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc(); +} + // FIXME: Ordering here? while (AdjustedTypeLoc TL = CurrTL.getAs()) CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); @@ -5767,7 +5773,10 @@ /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, -const ParsedAttr &Attr, Sema &S) { +const ParsedAttr &Attr, +TypeProcessingState &State) { + Sema &S = State.getSema(); + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be // qualified by an address-space qualifier." if (Type->isFunctionType()) { @@ -5809,10 +5818,15 @@ // the type. QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); -if (!T.isNull()) - Type = T;
[PATCH] D51229: [Sema/Attribute] Make types declared with address_space an AttributedType
leonardchan updated this revision to Diff 162711. leonardchan marked an inline comment as done. Repository: rC Clang https://reviews.llvm.org/D51229 Files: include/clang/Basic/Attr.td lib/AST/TypePrinter.cpp lib/Sema/SemaType.cpp Index: lib/Sema/SemaType.cpp === --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5597,12 +5597,6 @@ } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { -if (DependentAddressSpaceTypeLoc DASTL = -CurrTL.getAs()) { - fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs()); - CurrTL = DASTL.getPointeeTypeLoc().getUnqualifiedLoc(); -} - // An AtomicTypeLoc might be produced by an atomic qualifier in this // declarator chunk. if (AtomicTypeLoc ATL = CurrTL.getAs()) { @@ -5615,6 +5609,12 @@ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); } +while (DependentAddressSpaceTypeLoc TL = + CurrTL.getAs()) { + fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs()); + CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc(); +} + // FIXME: Ordering here? while (AdjustedTypeLoc TL = CurrTL.getAs()) CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); @@ -5767,7 +5767,10 @@ /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, -const ParsedAttr &Attr, Sema &S) { +const ParsedAttr &Attr, +TypeProcessingState &State) { + Sema &S = State.getSema(); + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be // qualified by an address-space qualifier." if (Type->isFunctionType()) { @@ -5809,10 +5812,15 @@ // the type. QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); -if (!T.isNull()) - Type = T; -else +if (!T.isNull()) { + ASTContext &Ctx = S.Context; + auto *ASAttr = ::new (Ctx) AddressSpaceAttr( + Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), + static_cast(T.getQualifiers().getAddressSpace())); + Type = State.getAttributedType(ASAttr, T, T); +} else { Attr.setInvalid(); +} } else { // The keyword-based type attributes imply which address space to use. switch (Attr.getKind()) { @@ -7282,7 +7290,7 @@ case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: case ParsedAttr::AT_AddressSpace: - HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); + HandleAddressSpaceTypeAttribute(type, attr, state); attr.setUsedAsTypeAttr(); break; OBJC_POINTER_TYPE_ATTRS_CASELIST: Index: lib/AST/TypePrinter.cpp === --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1427,6 +1427,12 @@ return; } + // The printing of the address_space attribute is handled by the qualifier + // since it is still stored in the qualifier. Return early to prevent printing + // this twice. + if (T->getAttrKind() == attr::AddressSpace) +return; + OS << " __attribute__(("; switch (T->getAttrKind()) { #define TYPE_ATTR(NAME) @@ -1456,6 +1462,7 @@ case attr::Ptr64: case attr::SPtr: case attr::UPtr: + case attr::AddressSpace: llvm_unreachable("This attribute should have been handled already"); case attr::NSReturnsRetained: Index: include/clang/Basic/Attr.td === --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -564,8 +564,6 @@ let Spellings = [Clang<"address_space">]; let Args = [IntArgument<"AddressSpace">]; let Documentation = [Undocumented]; - // Represented as a qualifier or DependentAddressSpaceType instead. - let ASTNode = 0; } def Alias : Attr { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51229: [Sema/Attribute] Make types declared with address_space an AttributedType
This revision was automatically updated to reflect the committed changes. Closed by commit rC340765: [Sema/Attribute] Make types declared with address_space an AttributedType (authored by leonardchan, committed by ). Repository: rC Clang https://reviews.llvm.org/D51229 Files: include/clang/Basic/Attr.td lib/AST/TypePrinter.cpp lib/Sema/SemaType.cpp Index: include/clang/Basic/Attr.td === --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -564,8 +564,6 @@ let Spellings = [Clang<"address_space">]; let Args = [IntArgument<"AddressSpace">]; let Documentation = [Undocumented]; - // Represented as a qualifier or DependentAddressSpaceType instead. - let ASTNode = 0; } def Alias : Attr { Index: lib/AST/TypePrinter.cpp === --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1427,6 +1427,12 @@ return; } + // The printing of the address_space attribute is handled by the qualifier + // since it is still stored in the qualifier. Return early to prevent printing + // this twice. + if (T->getAttrKind() == attr::AddressSpace) +return; + OS << " __attribute__(("; switch (T->getAttrKind()) { #define TYPE_ATTR(NAME) @@ -1456,6 +1462,7 @@ case attr::Ptr64: case attr::SPtr: case attr::UPtr: + case attr::AddressSpace: llvm_unreachable("This attribute should have been handled already"); case attr::NSReturnsRetained: Index: lib/Sema/SemaType.cpp === --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5597,12 +5597,6 @@ } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { -if (DependentAddressSpaceTypeLoc DASTL = -CurrTL.getAs()) { - fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs()); - CurrTL = DASTL.getPointeeTypeLoc().getUnqualifiedLoc(); -} - // An AtomicTypeLoc might be produced by an atomic qualifier in this // declarator chunk. if (AtomicTypeLoc ATL = CurrTL.getAs()) { @@ -5615,6 +5609,12 @@ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); } +while (DependentAddressSpaceTypeLoc TL = + CurrTL.getAs()) { + fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs()); + CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc(); +} + // FIXME: Ordering here? while (AdjustedTypeLoc TL = CurrTL.getAs()) CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); @@ -5767,7 +5767,10 @@ /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, -const ParsedAttr &Attr, Sema &S) { +const ParsedAttr &Attr, +TypeProcessingState &State) { + Sema &S = State.getSema(); + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be // qualified by an address-space qualifier." if (Type->isFunctionType()) { @@ -5809,10 +5812,15 @@ // the type. QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); -if (!T.isNull()) - Type = T; -else +if (!T.isNull()) { + ASTContext &Ctx = S.Context; + auto *ASAttr = ::new (Ctx) AddressSpaceAttr( + Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), + static_cast(T.getQualifiers().getAddressSpace())); + Type = State.getAttributedType(ASAttr, T, T); +} else { Attr.setInvalid(); +} } else { // The keyword-based type attributes imply which address space to use. switch (Attr.getKind()) { @@ -7282,7 +7290,7 @@ case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: case ParsedAttr::AT_AddressSpace: - HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); + HandleAddressSpaceTypeAttribute(type, attr, state); attr.setUsedAsTypeAttr(); break; OBJC_POINTER_TYPE_ATTRS_CASELIST: ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51329: [Attribute/Diagnostics] Print macro instead of whole attribute for address_space
leonardchan created this revision. leonardchan added reviewers: rsmith, rjmccall, ebevhan, mcgrathr, phosek. leonardchan added a project: clang. If an `address_space` attribute is defined in a macro, print the macro instead when diagnosing a warning or error for incompatible pointers with different address_spaces. Originally started from http://lists.llvm.org/pipermail/cfe-dev/2018-August/058702.html where the original proposal was a new pragma, but instead just changing the way `address_space` gets printed in a diagnostic. Repository: rC Clang https://reviews.llvm.org/D51329 Files: include/clang/AST/ASTContext.h include/clang/AST/Type.h include/clang/Lex/Preprocessor.h lib/AST/ASTContext.cpp lib/AST/TypePrinter.cpp lib/Lex/PPDirectives.cpp lib/Sema/SemaType.cpp test/Sema/address_space_print_macro.c test/Sema/address_spaces.c Index: test/Sema/address_spaces.c === --- test/Sema/address_spaces.c +++ test/Sema/address_spaces.c @@ -71,5 +71,5 @@ // Clang extension doesn't forbid operations on pointers to different address spaces. char* cmp(_AS1 char *x, _AS2 char *y) { - return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *') which are pointers to non-overlapping address spaces}} + return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}} } Index: test/Sema/address_space_print_macro.c === --- /dev/null +++ test/Sema/address_space_print_macro.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify + +#define _AS1 __attribute__((address_space(1))) +#define _AS2 __attribute__((address_space(2))) + +char *cmp(_AS1 char *x, _AS2 char *y) { + return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}} +} + +__attribute__((address_space(1))) char test_array[10]; +void test3(void) { + extern void test3_helper(char *p); // expected-note{{passing argument to parameter 'p' here}} + test3_helper(test_array); // expected-error{{passing '__attribute__((address_space(1))) char *' to parameter of type 'char *' changes address space of pointer}} +} + +char _AS2 *test4_array; +void test4(void) { + extern void test3_helper(char *p); // expected-note{{passing argument to parameter 'p' here}} + test3_helper(test4_array); // expected-error{{passing '_AS2 char *' to parameter of type 'char *' changes address space of pointer}} +} + +void func() { + char _AS1 *x; + char *y = x; // expected-error{{initializing 'char *' with an expression of type '_AS1 char *' changes address space of pointer}} +} Index: lib/Sema/SemaType.cpp === --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -243,9 +243,10 @@ /// Get an attributed type for the given attribute, and remember the Attr /// object so that we can attach it to the AttributedTypeLoc. QualType getAttributedType(Attr *A, QualType ModifiedType, - QualType EquivType) { - QualType T = - sema.Context.getAttributedType(A->getKind(), ModifiedType, EquivType); + QualType EquivType, + IdentifierInfo *AddressSpaceMacroII = nullptr) { + QualType T = sema.Context.getAttributedType( + A->getKind(), ModifiedType, EquivType, AddressSpaceMacroII); AttrsForTypes.push_back({cast(T.getTypePtr()), A}); AttrsForTypesSorted = false; return T; @@ -5813,11 +5814,17 @@ QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); if (!T.isNull()) { + IdentifierInfo *AddressSpaceMacroII = nullptr; + auto FoundMacro = S.PP.AddressSpaceMacros.find( + S.SourceMgr.getSpellingLoc(Attr.getLoc())); + if (FoundMacro != S.PP.AddressSpaceMacros.end()) +AddressSpaceMacroII = FoundMacro->second; + ASTContext &Ctx = S.Context; auto *ASAttr = ::new (Ctx) AddressSpaceAttr( Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), static_cast(T.getQualifiers().getAddressSpace())); - Type = State.getAttributedType(ASAttr, T, T); + Type = State.getAttributedType(ASAttr, T, T, AddressSpaceMacroII); } else { Attr.setInvalid(); } Index: lib/Lex/PPDirectives.cpp === --- lib/Lex/PPDirectives.cpp +++ lib/Lex/PPDirectives.cpp @@ -2577,6 +2577,22 @@ MI->setDefinitionEndLoc(LastTok.getLocation()); return MI; } + +static bool DefinesAddre