summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeonard Chan <leonardchan@google.com>2018-10-15 16:07:02 +0000
committerLeonard Chan <leonardchan@google.com>2018-10-15 16:07:02 +0000
commit99bda375a14e4c3b7d0adbc65293879899875fa6 (patch)
tree747ceecaefd44bb95aa2f5779772ee519f70c77e
parent06ba9f52460b06f83c9da505aa10fe01d9546945 (diff)
downloadbcm5719-llvm-99bda375a14e4c3b7d0adbc65293879899875fa6.tar.gz
bcm5719-llvm-99bda375a14e4c3b7d0adbc65293879899875fa6.zip
[Fixed Point Arithmetic] FixedPointCast
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. Differential Revision: https://reviews.llvm.org/D50616 llvm-svn: 344530
-rw-r--r--clang/include/clang/AST/OperationKinds.def4
-rw-r--r--clang/include/clang/AST/Type.h3
-rw-r--r--clang/include/clang/Basic/DiagnosticCommonKinds.td2
-rw-r--r--clang/lib/AST/Expr.cpp1
-rw-r--r--clang/lib/AST/ExprConstant.cpp2
-rw-r--r--clang/lib/AST/Type.cpp1
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp111
-rw-r--r--clang/lib/Edit/RewriteObjCFoundationAPI.cpp3
-rw-r--r--clang/lib/Sema/Sema.cpp2
-rw-r--r--clang/lib/Sema/SemaExpr.cpp52
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp3
-rw-r--r--clang/test/Frontend/fixed_point_conversions.c283
-rw-r--r--clang/test/Frontend/fixed_point_unknown_conversions.c50
17 files changed, 517 insertions, 4 deletions
diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def
index e2d65d84880..47b8d67af2d 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -197,6 +197,10 @@ CAST_OPERATION(IntegralToBoolean)
/// float f = i;
CAST_OPERATION(IntegralToFloating)
+/// CK_FixedPointCast - Fixed point to fixed point.
+/// (_Accum) 0.5r
+CAST_OPERATION(FixedPointCast)
+
/// CK_FloatingToIntegral - Floating point to integral. Rounds
/// towards zero, discarding any fractional component.
/// (int) f
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 369ce6dfa1c..cbcce8832e7 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2066,7 +2066,8 @@ public:
STK_Integral,
STK_Floating,
STK_IntegralComplex,
- STK_FloatingComplex
+ STK_FloatingComplex,
+ STK_FixedPoint
};
/// Given that this is a scalar type, classify it.
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index c3e2aa8b5c3..f0aff9a188c 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -172,6 +172,8 @@ def err_too_large_for_fixed_point : Error<
"this value is too large for this fixed point type">;
def err_fixed_point_not_enabled : Error<"compile with "
"'-ffixed-point' to enable fixed point types">;
+def err_unimplemented_conversion_with_fixed_point_type : Error<
+ "conversion between fixed point and %0 is not yet supported">;
// SEH
def err_seh_expected_handler : Error<
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 651981374d4..b9606876e43 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1644,6 +1644,7 @@ bool CastExpr::CastConsistency() const {
case CK_ZeroToOCLEvent:
case CK_ZeroToOCLQueue:
case CK_IntToOCLSampler:
+ case CK_FixedPointCast:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d2258cc2124..de0de5d13cd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9556,6 +9556,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_NonAtomicToAtomic:
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
+ case CK_FixedPointCast:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -10090,6 +10091,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_NonAtomicToAtomic:
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
+ case CK_FixedPointCast:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 1b4b84d030f..08f91c6ca99 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1965,6 +1965,7 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const {
if (BT->getKind() == BuiltinType::NullPtr) return STK_CPointer;
if (BT->isInteger()) return STK_Integral;
if (BT->isFloatingPoint()) return STK_Floating;
+ if (BT->isFixedPointType()) return STK_FixedPoint;
llvm_unreachable("unknown scalar builtin type");
} else if (isa<PointerType>(T)) {
return STK_CPointer;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 028aa963cda..55fa4551167 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4153,6 +4153,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_CopyAndAutoreleaseBlockObject:
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
+ case CK_FixedPointCast:
return EmitUnsupportedLValue(E, "unexpected cast lvalue");
case CK_Dependent:
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 62641102861..9e809872ce9 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -851,6 +851,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_ZeroToOCLQueue:
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
+ case CK_FixedPointCast:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index fb176093a74..1d5438668bb 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -509,6 +509,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
case CK_ZeroToOCLQueue:
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
+ case CK_FixedPointCast:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 651b05a26f7..3dbb20dab2a 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -871,6 +871,7 @@ public:
case CK_FloatingCast:
case CK_ZeroToOCLEvent:
case CK_ZeroToOCLQueue:
+ case CK_FixedPointCast:
return nullptr;
}
llvm_unreachable("Invalid CastKind");
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 0bbd788f028..3abb26991a4 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
-#include "CGCleanup.h"
#include "CGCXXABI.h"
+#include "CGCleanup.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
@@ -23,6 +23,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/FixedPoint.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/Optional.h"
@@ -327,6 +328,9 @@ public:
SourceLocation Loc,
ScalarConversionOpts Opts = ScalarConversionOpts());
+ Value *EmitFixedPointConversion(Value *Src, QualType SrcTy, QualType DstTy,
+ SourceLocation Loc);
+
/// 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,
@@ -1011,6 +1015,10 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
QualType DstType,
SourceLocation Loc,
ScalarConversionOpts Opts) {
+ assert(!SrcType->isFixedPointType() && !DstType->isFixedPointType() &&
+ "Use the ScalarExprEmitter::EmitFixedPoint family functions for "
+ "handling conversions involving fixed point types.");
+
QualType NoncanonicalSrcType = SrcType;
QualType NoncanonicalDstType = DstType;
@@ -1204,6 +1212,101 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Res;
}
+Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
+ QualType DstTy,
+ SourceLocation Loc) {
+ using llvm::APInt;
+ using llvm::ConstantInt;
+ using llvm::Value;
+
+ assert(SrcTy->isFixedPointType());
+ assert(DstTy->isFixedPointType());
+
+ FixedPointSemantics SrcFPSema =
+ CGF.getContext().getFixedPointSemantics(SrcTy);
+ FixedPointSemantics DstFPSema =
+ CGF.getContext().getFixedPointSemantics(DstTy);
+ unsigned SrcWidth = SrcFPSema.getWidth();
+ unsigned DstWidth = DstFPSema.getWidth();
+ unsigned SrcScale = SrcFPSema.getScale();
+ unsigned DstScale = DstFPSema.getScale();
+ bool IsSigned = SrcFPSema.isSigned();
+
+ Value *Result = Src;
+ unsigned ResultWidth = SrcWidth;
+
+ if (!DstFPSema.isSaturated()) {
+ // Downscale
+ if (DstScale < SrcScale) {
+ if (IsSigned)
+ Result = Builder.CreateAShr(Result, SrcScale - DstScale);
+ else
+ Result = Builder.CreateLShr(Result, SrcScale - DstScale);
+ }
+
+ // Resize
+ llvm::Type *DstIntTy = Builder.getIntNTy(DstWidth);
+ if (IsSigned)
+ Result = Builder.CreateSExtOrTrunc(Result, DstIntTy);
+ else
+ Result = Builder.CreateZExtOrTrunc(Result, DstIntTy);
+
+ // Upscale
+ if (DstScale > SrcScale)
+ Result = Builder.CreateShl(Result, DstScale - SrcScale);
+ } else {
+ if (DstScale > SrcScale) {
+ // Need to extend first before scaling up
+ ResultWidth = SrcWidth + DstScale - SrcScale;
+ llvm::Type *UpscaledTy = Builder.getIntNTy(ResultWidth);
+
+ if (IsSigned)
+ Result = Builder.CreateSExt(Result, UpscaledTy);
+ else
+ Result = Builder.CreateZExt(Result, UpscaledTy);
+
+ Result = Builder.CreateShl(Result, DstScale - SrcScale);
+ } else if (DstScale < SrcScale) {
+ if (IsSigned)
+ Result = Builder.CreateAShr(Result, SrcScale - DstScale);
+ else
+ Result = Builder.CreateLShr(Result, SrcScale - DstScale);
+ }
+
+ if (DstFPSema.getIntegralBits() < SrcFPSema.getIntegralBits()) {
+ auto Max = ConstantInt::get(
+ CGF.getLLVMContext(),
+ APFixedPoint::getMax(DstFPSema).getValue().extOrTrunc(ResultWidth));
+ Value *TooHigh = IsSigned ? Builder.CreateICmpSGT(Result, Max)
+ : Builder.CreateICmpUGT(Result, Max);
+ Result = Builder.CreateSelect(TooHigh, Max, Result);
+
+ if (IsSigned) {
+ // Cannot overflow min to dest type is src is unsigned since all fixed
+ // point types can cover the unsigned min of 0.
+ auto Min = ConstantInt::get(
+ CGF.getLLVMContext(),
+ APFixedPoint::getMin(DstFPSema).getValue().extOrTrunc(ResultWidth));
+ Value *TooLow = Builder.CreateICmpSLT(Result, Min);
+ Result = Builder.CreateSelect(TooLow, Min, Result);
+ }
+ } else if (IsSigned && !DstFPSema.isSigned()) {
+ llvm::Type *ResultTy = Builder.getIntNTy(ResultWidth);
+ Value *Zero = ConstantInt::getNullValue(ResultTy);
+ Value *LTZero = Builder.CreateICmpSLT(Result, Zero);
+ Result = Builder.CreateSelect(LTZero, Zero, Result);
+ }
+
+ // Final resizing to dst width
+ llvm::Type *DstIntTy = Builder.getIntNTy(DstWidth);
+ if (IsSigned)
+ Result = Builder.CreateSExtOrTrunc(Result, DstIntTy);
+ else
+ Result = Builder.CreateZExtOrTrunc(Result, DstIntTy);
+ }
+ return Result;
+}
+
/// Emit a conversion from the specified complex type to the specified
/// destination type, where the destination type is an LLVM scalar type.
Value *ScalarExprEmitter::EmitComplexToScalarConversion(
@@ -1894,6 +1997,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return Builder.CreateVectorSplat(NumElements, Elt, "splat");
}
+ case CK_FixedPointCast:
+ return EmitFixedPointConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc());
+
case CK_IntegralCast: {
ScalarConversionOpts Opts;
if (CGF.SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)) {
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 3a305ecd94e..e18c488d877 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1085,6 +1085,9 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_BooleanToSignedIntegral:
llvm_unreachable("OpenCL-specific cast in Objective-C?");
+
+ case CK_FixedPointCast:
+ llvm_unreachable("Fixed point types are disabled for Objective-C");
}
}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 916f23c1caa..7e162029888 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -533,6 +533,8 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) {
case Type::STK_Floating: return CK_FloatingToBoolean;
case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean;
case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean;
+ case Type::STK_FixedPoint:
+ llvm_unreachable("Unknown cast from FixedPoint to boolean");
}
llvm_unreachable("unknown scalar type kind");
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 8144b3a7796..72499b0e905 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5884,10 +5884,36 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_FloatingComplex:
case Type::STK_IntegralComplex:
case Type::STK_MemberPointer:
+ case Type::STK_FixedPoint:
llvm_unreachable("illegal cast from pointer");
}
llvm_unreachable("Should have returned before this");
+ case Type::STK_FixedPoint:
+ switch (DestTy->getScalarTypeKind()) {
+ case Type::STK_FixedPoint:
+ return CK_FixedPointCast;
+ case Type::STK_Bool:
+ Diag(Src.get()->getExprLoc(),
+ diag::err_unimplemented_conversion_with_fixed_point_type)
+ << DestTy;
+ return CK_IntegralToBoolean;
+ case Type::STK_Integral:
+ case Type::STK_Floating:
+ case Type::STK_IntegralComplex:
+ case Type::STK_FloatingComplex:
+ Diag(Src.get()->getExprLoc(),
+ diag::err_unimplemented_conversion_with_fixed_point_type)
+ << DestTy;
+ return CK_IntegralCast;
+ case Type::STK_CPointer:
+ case Type::STK_ObjCObjectPointer:
+ case Type::STK_BlockPointer:
+ case Type::STK_MemberPointer:
+ llvm_unreachable("illegal cast to pointer type");
+ }
+ llvm_unreachable("Should have returned before this");
+
case Type::STK_Bool: // casting from bool is like casting from an integer
case Type::STK_Integral:
switch (DestTy->getScalarTypeKind()) {
@@ -5916,6 +5942,11 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
return CK_FloatingRealToComplex;
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
+ case Type::STK_FixedPoint:
+ Diag(Src.get()->getExprLoc(),
+ diag::err_unimplemented_conversion_with_fixed_point_type)
+ << SrcTy;
+ return CK_IntegralCast;
}
llvm_unreachable("Should have returned before this");
@@ -5943,6 +5974,11 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
llvm_unreachable("valid float->pointer cast?");
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
+ case Type::STK_FixedPoint:
+ Diag(Src.get()->getExprLoc(),
+ diag::err_unimplemented_conversion_with_fixed_point_type)
+ << SrcTy;
+ return CK_IntegralCast;
}
llvm_unreachable("Should have returned before this");
@@ -5972,6 +6008,11 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
llvm_unreachable("valid complex float->pointer cast?");
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
+ case Type::STK_FixedPoint:
+ Diag(Src.get()->getExprLoc(),
+ diag::err_unimplemented_conversion_with_fixed_point_type)
+ << SrcTy;
+ return CK_IntegralCast;
}
llvm_unreachable("Should have returned before this");
@@ -6001,6 +6042,11 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
llvm_unreachable("valid complex int->pointer cast?");
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
+ case Type::STK_FixedPoint:
+ Diag(Src.get()->getExprLoc(),
+ diag::err_unimplemented_conversion_with_fixed_point_type)
+ << SrcTy;
+ return CK_IntegralCast;
}
llvm_unreachable("Should have returned before this");
}
@@ -12747,6 +12793,12 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Context.getLangOpts().CPlusPlus) {
// C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9:
// operand contextually converted to bool.
+ if (resultType->getScalarTypeKind() == Type::STK_FixedPoint) {
+ return ExprError(
+ Diag(Input.get()->getExprLoc(),
+ diag::err_unimplemented_conversion_with_fixed_point_type)
+ << resultType);
+ }
Input = ImpCastExprToType(Input.get(), Context.BoolTy,
ScalarTypeToBooleanCastKind(resultType));
} else if (Context.getLangOpts().OpenCL &&
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 61b7a290e42..f40a8d9a546 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -415,7 +415,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_ZeroToOCLEvent:
case CK_ZeroToOCLQueue:
case CK_IntToOCLSampler:
- case CK_LValueBitCast: {
+ case CK_LValueBitCast:
+ case CK_FixedPointCast: {
state =
handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred);
continue;
diff --git a/clang/test/Frontend/fixed_point_conversions.c b/clang/test/Frontend/fixed_point_conversions.c
new file mode 100644
index 00000000000..4064ac5d2cb
--- /dev/null
+++ b/clang/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: [[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 i32
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = shl i32 [[SACCUM_BUFF]], 8
+ // DEFAULT-NEXT: store i32 [[ACCUM]], 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 i64
+ // DEFAULT-NEXT: [[LACCUM:%[0-9]+]] = shl i64 [[ACCUM_BUFF]], 16
+ // DEFAULT-NEXT: store i64 [[LACCUM]], 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 i32
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = shl i32 [[SACCUM_BUFF]], 8
+ // DEFAULT-NEXT: store i32 [[ACCUM]], 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 i64
+ // DEFAULT-NEXT: [[LACCUM:%[0-9]+]] = shl i64 [[ACCUM_BUFF]], 16
+ // DEFAULT-NEXT: store i64 [[LACCUM]], 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: [[UACCUM:%[0-9]+]] = shl i32 [[ACCUM]], 1
+ // DEFAULT-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
+ // SAME: TestFixedPointCastSignedness
+ // SAME: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4
+ // SAME-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
+
+ a = ua;
+ // DEFAULT: [[UACCUM:%[0-9]+]] = load i32, i32* %ua, align 4
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = lshr i32 [[UACCUM]], 1
+ // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+ // SAME: [[ACCUM:%[0-9]+]] = load i32, i32* %ua, align 4
+ // SAME-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+
+ ua = (unsigned _Accum)a;
+ // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4
+ // DEFAULT-NEXT: [[UACCUM:%[0-9]+]] = shl i32 [[ACCUM]], 1
+ // DEFAULT-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
+
+ a = (_Accum)ua;
+ // DEFAULT: [[UACCUM:%[0-9]+]] = load i32, i32* %ua, align 4
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = lshr i32 [[UACCUM]], 1
+ // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+
+ _Accum a2;
+ unsigned long _Accum ula = a2;
+ // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a2, align 4
+ // DEFAULT-NEXT: [[ACCUM_EXT:%[0-9]+]] = sext i32 [[ACCUM]] to i64
+ // DEFAULT-NEXT: [[LACCUM:%[0-9]+]] = shl i64 [[ACCUM_EXT]], 17
+ // DEFAULT-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
+ // SAME: [[ACCUM:%[0-9]+]] = load i32, i32* %a2, align 4
+ // SAME-NEXT: [[ACCUM_EXT:%[0-9]+]] = sext i32 [[ACCUM]] to i64
+ // SAME-NEXT: [[LACCUM:%[0-9]+]] = shl i64 [[ACCUM_EXT]], 16
+ // SAME-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
+}
+
+void TestFixedPointCastSaturation() {
+ _Accum a;
+ _Sat short _Accum sat_sa;
+ _Sat _Accum sat_a;
+ _Sat long _Accum sat_la;
+ _Sat unsigned short _Accum sat_usa;
+ _Sat unsigned _Accum sat_ua;
+ _Sat unsigned long _Accum sat_ula;
+ _Sat short _Fract sat_sf;
+ _Sat _Fract sat_f;
+ _Sat long _Fract sat_lf;
+
+ // Casting down between types
+ sat_sa = sat_a;
+ // DEFAULT: [[OLD_ACCUM:%[0-9]+]] = load i32, i32* %sat_a, align 4
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = ashr i32 [[OLD_ACCUM]], 8
+ // DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i32 [[ACCUM]], 32767
+ // DEFAULT-NEXT: [[RESULT:%[0-9]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
+ // DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i32 [[RESULT]], -32768
+ // DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
+ // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9]+]] = trunc i32 [[RESULT2]] to i16
+ // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_sa, align 2
+
+ // Accum to Fract, decreasing scale
+ sat_sf = sat_a;
+ // DEFAULT: [[OLD_ACCUM:%[0-9]+]] = load i32, i32* %sat_a, align 4
+ // DEFAULT-NEXT: [[FRACT:%[0-9]+]] = ashr i32 [[OLD_ACCUM]], 8
+ // DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i32 [[FRACT]], 127
+ // DEFAULT-NEXT: [[RESULT:%[0-9]+]] = select i1 [[USE_MAX]], i32 127, i32 [[FRACT]]
+ // DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i32 [[RESULT]], -128
+ // DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MIN]], i32 -128, i32 [[RESULT]]
+ // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9]+]] = trunc i32 [[RESULT2]] to i8
+ // DEFAULT-NEXT: store i8 [[RESULT_TRUNC]], i8* %sat_sf, align 1
+
+ // Accum to Fract, same scale
+ sat_f = a;
+ // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4
+ // DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i32 [[ACCUM]], 32767
+ // DEFAULT-NEXT: [[RESULT:%[0-9]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
+ // DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i32 [[RESULT]], -32768
+ // DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
+ // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9]+]] = trunc i32 [[RESULT2]] to i16
+ // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_f, align 2
+
+ // Accum to Fract, increasing scale
+ sat_lf = sat_a;
+ // DEFAULT: [[OLD_ACCUM:%[0-9]+]] = load i32, i32* %sat_a, align 4
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = sext i32 [[OLD_ACCUM]] to i48
+ // DEFAULT-NEXT: [[FRACT:%[0-9]+]] = shl i48 [[ACCUM]], 16
+ // DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i48 [[FRACT]], 2147483647
+ // DEFAULT-NEXT: [[RESULT:%[0-9]+]] = select i1 [[USE_MAX]], i48 2147483647, i48 [[FRACT]]
+ // DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i48 [[RESULT]], -2147483648
+ // DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MIN]], i48 -2147483648, i48 [[RESULT]]
+ // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9]+]] = trunc i48 [[RESULT2]] to i32
+ // DEFAULT-NEXT: store i32 [[RESULT_TRUNC]], i32* %sat_lf, align 4
+
+ // Signed to unsigned, decreasing scale
+ _Sat _Accum sat_a2;
+ sat_usa = sat_a2;
+ // DEFAULT: [[OLD_ACCUM:%[0-9]+]] = load i32, i32* %sat_a2, align 4
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = ashr i32 [[OLD_ACCUM]], 7
+ // DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i32 [[ACCUM]], 65535
+ // DEFAULT-NEXT: [[RESULT:%[0-9]+]] = select i1 [[USE_MAX]], i32 65535, i32 [[ACCUM]]
+ // DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i32 [[RESULT]], 0
+ // DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
+ // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9]+]] = trunc i32 [[RESULT2]] to i16
+ // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
+ // SAME: [[OLD_ACCUM:%[0-9]+]] = load i32, i32* %sat_a2, align 4
+ // SAME-NEXT: [[ACCUM:%[0-9]+]] = ashr i32 [[OLD_ACCUM]], 8
+ // SAME-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i32 [[ACCUM]], 32767
+ // SAME-NEXT: [[RESULT:%[0-9]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
+ // SAME-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i32 [[RESULT]], 0
+ // SAME-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
+ // SAME-NEXT: [[RESULT_TRUNC:%[0-9]+]] = trunc i32 [[RESULT2]] to i16
+ // SAME-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
+
+ // Signed to unsigned, increasing scale
+ sat_ua = sat_a;
+ // DEFAULT: [[OLD_ACCUM:%[0-9]+]] = load i32, i32* %sat_a, align 4
+ // DEFAULT-NEXT: [[ACCUM_EXT:%[0-9]+]] = sext i32 [[OLD_ACCUM]] to i33
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = shl i33 [[ACCUM_EXT]], 1
+ // DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i33 [[ACCUM]], 0
+ // DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MIN]], i33 0, i33 [[ACCUM]]
+ // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9]+]] = trunc i33 [[RESULT2]] to i32
+ // DEFAULT-NEXT: store i32 [[RESULT_TRUNC]], i32* %sat_ua, align 4
+ // SAME: [[ACCUM:%[0-9]+]] = load i32, i32* %sat_a, align 4
+ // SAME-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i32 [[ACCUM]], 0
+ // SAME-NEXT: [[RESULT:%[0-9]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACCUM]]
+ // SAME-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
+
+ // Nothing when saturating to the same type and size
+ sat_a = a;
+ // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4
+ // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %sat_a, align 4
+
+ // Nothing when assigning back
+ a = sat_a;
+ // DEFAULT: [[SAT_ACCUM:%[0-9]+]] = load i32, i32* %sat_a, align 4
+ // DEFAULT-NEXT: store i32 [[SAT_ACCUM]], i32* %a, align 4
+
+ // No overflow when casting from fract to signed accum
+ sat_a = sat_f;
+ // DEFAULT: [[FRACT:%[0-9]+]] = load i16, i16* %sat_f, align 2
+ // DEFAULT-NEXT: [[FRACT_EXT:%[0-9]+]] = sext i16 [[FRACT]] to i32
+ // DEFAULT-NEXT: store i32 [[FRACT_EXT]], i32* %sat_a, align 4
+
+ // Only get overflow checking if signed fract to unsigned accum
+ sat_ua = sat_sf;
+ // DEFAULT: [[FRACT:%[0-9]+]] = load i8, i8* %sat_sf, align 1
+ // DEFAULT-NEXT: [[FRACT_EXT:%[0-9]+]] = sext i8 [[FRACT]] to i17
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = shl i17 [[FRACT_EXT]], 9
+ // DEFAULT-NEXT: [[IS_NEG:%[0-9]+]] = icmp slt i17 [[ACCUM]], 0
+ // DEFAULT-NEXT: [[RESULT:%[0-9]+]] = select i1 [[IS_NEG]], i17 0, i17 [[ACCUM]]
+ // DEFAULT-NEXT: [[RESULT_EXT:%[0-9]+]] = sext i17 [[RESULT]] to i32
+ // DEFAULT-NEXT: store i32 [[RESULT_EXT]], i32* %sat_ua, align 4
+ // SAME: [[FRACT:%[0-9]+]] = load i8, i8* %sat_sf, align 1
+ // SAME-NEXT: [[FRACT_EXT:%[0-9]+]] = sext i8 [[FRACT]] to i16
+ // SAME-NEXT: [[ACCUM:%[0-9]+]] = shl i16 [[FRACT_EXT]], 8
+ // SAME-NEXT: [[IS_NEG:%[0-9]+]] = icmp slt i16 [[ACCUM]], 0
+ // SAME-NEXT: [[RESULT:%[0-9]+]] = select i1 [[IS_NEG]], i16 0, i16 [[ACCUM]]
+ // SAME-NEXT: [[RESULT_EXT:%[0-9]+]] = sext i16 [[RESULT]] to i32
+ // SAME-NEXT: store i32 [[RESULT_EXT]], i32* %sat_ua, align 4
+}
+
+void TestFixedPointCastBetFractAccum() {
+ short _Accum sa;
+ _Accum a;
+ long _Accum la;
+ short _Fract sf;
+ _Fract f;
+ long _Fract lf;
+ unsigned _Accum ua;
+ unsigned _Fract uf;
+
+ // To lower scale
+ sf = a;
+ // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4
+ // DEFAULT-NEXT: [[FRACT:%[0-9]+]] = ashr i32 [[ACCUM]], 8
+ // DEFAULT-NEXT: [[FRACT_TRUNC:%[0-9]+]] = trunc i32 [[FRACT]] to i8
+ // DEFAULT-NEXT: store i8 [[FRACT_TRUNC]], i8* %sf, align 1
+
+ // To higher scale
+ a = sf;
+ // DEFAULT: [[FRACT:%[0-9]+]] = load i8, i8* %sf, align 1
+ // DEFAULT-NEXT: [[FRACT_EXT:%[0-9]+]] = sext i8 [[FRACT]] to i32
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = shl i32 [[FRACT_EXT]], 8
+ // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+
+ // To same scale
+ f = a;
+ // DEFAULT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4
+ // DEFAULT-NEXT: [[FRACT:%[0-9]+]] = trunc i32 [[ACCUM]] to i16
+ // DEFAULT-NEXT: store i16 [[FRACT]], i16* %f, align 2
+
+ a = f;
+ // DEFAULT: [[FRACT:%[0-9]+]] = load i16, i16* %f, align 2
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = sext i16 [[FRACT]] to i32
+ // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+
+ // To unsigned
+ ua = uf;
+ // DEFAULT: [[FRACT:%[0-9]+]] = load i16, i16* %uf, align 2
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = zext i16 [[FRACT]] to i32
+ // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
+ // SAME: [[FRACT:%[0-9]+]] = load i16, i16* %uf, align 2
+ // SAME-NEXT: [[ACCUM:%[0-9]+]] = zext i16 [[FRACT]] to i32
+ // SAME-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
+
+ uf = ua;
+ // DEFAULT: [[FRACT:%[0-9]+]] = load i32, i32* %ua, align 4
+ // DEFAULT-NEXT: [[ACCUM:%[0-9]+]] = trunc i32 [[FRACT]] to i16
+ // DEFAULT-NEXT: store i16 [[ACCUM]], i16* %uf, align 2
+ // SAME: [[FRACT:%[0-9]+]] = load i32, i32* %ua, align 4
+ // SAME-NEXT: [[ACCUM:%[0-9]+]] = trunc i32 [[FRACT]] to i16
+ // SAME-NEXT: store i16 [[ACCUM]], i16* %uf, align 2
+}
diff --git a/clang/test/Frontend/fixed_point_unknown_conversions.c b/clang/test/Frontend/fixed_point_unknown_conversions.c
new file mode 100644
index 00000000000..94b1fc32e9b
--- /dev/null
+++ b/clang/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}}
+}
OpenPOWER on IntegriCloud