leonardchan added a comment.

I ended up adding a lot to this patch, so feel free to let me know if I should 
split this up if it's more difficult to review.

Changes:

- Remove default ctors for `APFixedPoint` and `FixedPointSemantics`. The main 
reason I had these was so in the `EvaluateAsFixedPoint*` functions, I could 
pass in an `APFixedPoint` by reference that could be assigned on successful 
evaluation. But it feels more correct now to instead just use an `APValue`.
- Allow `APFixedPoint` to be contained in `APValue`. This takes up a bulk of 
the new changes and could be it's own patch.
- `FixedPointExprEvaluator` now calculates an `APValue` that holds an 
`APFixedPoint`.
- Removed unused `Success` methods in `FixedPointExprEvaluator`.
- Added `EvaluateAsFixedPoint` functions and method to `Expr`.
- Added tests for constant-evaluating fixed point conversions.
- Added warning for potential overflow conversions when assigning to fixed 
point types (as a part of adding tests for conversions)
- `APFixedPoint` `convert()` and `add()` methods take an optional second 
argument for indicating if the operation resulted in an overflow (although this 
could be changed for a clearer way to check for operator overflow)



================
Comment at: clang/include/clang/Basic/FixedPoint.h:98
  public:
+   APFixedPoint() = default;
    APFixedPoint(const llvm::APInt &Val, const FixedPointSemantics &Sema)
----------------
ebevhan wrote:
> rjmccall wrote:
> > This should be documented to describe what it does.  Does it create a value 
> > with impossible semantics?  Some reasonable default value in some 
> > reasonable default semantics?
> As it is, it doesn't seem to create anything useful; neither does the one for 
> the `FixedPointSemantics`. It would be a zero-width, zero-scale value.
The idea behind this was to enable a value to later be reassigned to an 
APFixedPoint, similar to how APValues are assigned in `EvaluateInteger` on 
success. I suppose the correct thing to do in this case would be to instead 
allow for APValue to take an APFixedPoint instead and pass that to 
`EvaluateFixedPoint*` to make it consistent with the other Evaluate methods and 
allow for APFixedPoint to be initialized with a default value.


================
Comment at: clang/lib/AST/ExprConstant.cpp:9953
+      return false;
+    APFixedPoint Result = Src.convert(DestFXSema);
+    return Success(Result, E);
----------------
rjmccall wrote:
> Can a fixed-point conversion ever have undefined behavior?  If so, you might 
> need to flag that as a failed case, unless we want to give it defined 
> semantics in Clang.
Yup. Overflow can happen for some non-saturating operations. Added.


================
Comment at: clang/lib/AST/ExprConstant.cpp:9955
+    return Success(Result, E);
+  }
+  default:
----------------
ebevhan wrote:
> rjmccall wrote:
> > Do you not have a separate `CK_IntegralToFixedPoint`?  It's convenient 
> > here, but still, it's curious.
> > 
> > You also need a `CK_FloatingToFixedPoint`, I think.  (Obviously you don't 
> > need to implement that right now.)
> Both of those should exist. I think that the `FixedPointCast` evaluation 
> should only use `EvaluateFixedPoint`.
I have not yet added either of those but will do so in other patches.


================
Comment at: clang/lib/AST/ExprConstant.cpp:9959
+  }
+  llvm_unreachable("unknown cast resulting in fixed point value");
+}
----------------
rjmccall wrote:
> This is obviously unreachable because of the `default` case in the `switch`.  
> Should this be moved into the `default` case, and then you can put your 
> `Error` call in cases for the known-missing fixed-point conversions?
> 
> You should go ahead and add cases for `CK_NoOp` and `CK_LValueToRValue`, they 
> should be obvious from the other evaluators.
> 
> You should add tests for constant-evaluating fixed-point conversions.
I think it would be better to keep it as an error since elsewhere, we emit 
errors indicating a particular operation or conversion has not yet been 
implemented.


================
Comment at: clang/lib/AST/ExprConstant.cpp:9977
+    APFixedPoint Result = LHSFX.add(RHSFX).convert(ResultFXSema);
+    return Success(Result, E);
+  }
----------------
ebevhan wrote:
> I understand the benefit of placing the actual operation implementation in 
> the `APFixedPoint` class, but it means that any intermediate information is 
> sort of lost. For example, if we want to warn the user about overflow (into 
> the padding bit, or just in general) we can't, because that information was 
> hidden.
> 
> I guess it could be done by checking if the result of the `add` is equal to 
> the result of the `convert` for non-saturating `ResultFXSema`? The 
> `APFixedPoint` comparison is value-based. Not sure how it would work with the 
> padding bit in unsigned types, though.
We could do something like having a separate method that checks for overflow or 
like `bool addCanOverflow(APFixedPoint LHS, APFixedPoint RHS)`, or an 
additional optional pointer argument to the add method like `APFixedPoint 
add(const APFixedPoint &Other, bool *overflow=nullptr)` where if `overflow` is 
not a nullptr, we would still perform the addition but set this to indicate if 
we overflowed or not. 

For now I went with the second option since this is useful now for checking 
overflow on casts and addition, but this could also be discussed/changed later.


================
Comment at: clang/lib/AST/ExprConstant.cpp:9982
+  }
+  llvm_unreachable("Should've exited before this");
+}
----------------
rjmccall wrote:
> This `unreachable` seems more reasonable since you're probably never going to 
> make this a covered `switch`.
Should I just remove these? I recall seeing some other switch statements in 
clang where after all cases are covered, there's an llvm_unreachable and I only 
put this here for consistency.


================
Comment at: clang/lib/Basic/FixedPoint.cpp:42
 
-    if (!DstSema.isSigned() && NewVal.isNegative())
+    if (!DstSema.isSigned() && NewVal.isSigned() && NewVal.isNegative())
       NewVal = 0;
----------------
ebevhan wrote:
> Maybe add a comment here to clarify what we are catching.
Added. I didn't know this before, but it turns out that `isNegative()` only 
checks if the last bit is set, but not if the value is signed or not.


================
Comment at: clang/test/Frontend/fixed_point_add.c:5
+// Addition between different fixed point types
+short _Accum sa_const = 1.0hk + 2.0hk;  // CHECK-DAG: @sa_const  = 
{{.*}}global i16 384, align 2
+_Accum a_const = 1.0hk + 2.0k;          // CHECK-DAG: @a_const   = 
{{.*}}global i32 98304, align 4
----------------
ebevhan wrote:
> The test doesn't have a triple so the alignment might be affected by what 
> machine the test runs on.
> 
> Now that I think about it, so will the results of the calculations, and the 
> emitted IR in the functions.
Added


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55868/new/

https://reviews.llvm.org/D55868



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to