Commit ec2ea85f authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] remove support for implicit branching on macros with labels

Now that we can short-circuit control flow in the optimizing compiler,
there is no more need for BranchIf... macros in CSA/Torque.
Thus removing support for them in Torque and rewriting Torque macros to
use bool return values instead.

Bug: v8:7793
Change-Id: Ie4b7522aa5558be038fe821d8b5d02859d522ed1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1724211
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63079}
parent 900f3a5d
...@@ -86,29 +86,25 @@ namespace array_join { ...@@ -86,29 +86,25 @@ namespace array_join {
// (see LoadJoinElement<ElementsAccessor>). // (see LoadJoinElement<ElementsAccessor>).
macro CannotUseSameArrayAccessor<T: type>(implicit context: Context)( macro CannotUseSameArrayAccessor<T: type>(implicit context: Context)(
loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map, loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map,
originalLen: Number): never originalLen: Number): bool;
labels Cannot, Can;
CannotUseSameArrayAccessor<JSArray>(implicit context: Context)( CannotUseSameArrayAccessor<JSArray>(implicit context: Context)(
loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map, loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map,
originalLen: Number): never originalLen: Number): bool {
labels Cannot, Can { if (loadFn == LoadJoinElement<array::GenericElementsAccessor>) return false;
if (loadFn == LoadJoinElement<array::GenericElementsAccessor>) goto Can;
const array: JSArray = UnsafeCast<JSArray>(receiver); const array: JSArray = UnsafeCast<JSArray>(receiver);
if (originalMap != array.map) goto Cannot; if (originalMap != array.map) return true;
if (originalLen != array.length) goto Cannot; if (originalLen != array.length) return true;
if (IsNoElementsProtectorCellInvalid()) goto Cannot; if (IsNoElementsProtectorCellInvalid()) return true;
goto Can; return false;
} }
CannotUseSameArrayAccessor<JSTypedArray>(implicit context: Context)( CannotUseSameArrayAccessor<JSTypedArray>(implicit context: Context)(
_loadFn: LoadJoinElementFn, receiver: JSReceiver, _initialMap: Map, _loadFn: LoadJoinElementFn, receiver: JSReceiver, _initialMap: Map,
_initialLen: Number): never _initialLen: Number): bool {
labels Cannot, Can {
const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver); const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
if (IsDetachedBuffer(typedArray.buffer)) goto Cannot; return IsDetachedBuffer(typedArray.buffer);
goto Can;
} }
// Calculates the running total length of the resulting string. If the // Calculates the running total length of the resulting string. If the
...@@ -465,11 +461,9 @@ namespace array_join { ...@@ -465,11 +461,9 @@ namespace array_join {
} }
// Fast path the common non-nested calls. If the receiver is not already on // Fast path the common non-nested calls. If the receiver is not already on
// the stack, add it to the stack and go to ReceiverAdded. Otherwise go to // the stack, add it to the stack and return true. Otherwise return false.
// ReceiverNotAdded.
macro JoinStackPushInline(implicit context: Context)(receiver: JSReceiver): macro JoinStackPushInline(implicit context: Context)(receiver: JSReceiver):
never bool {
labels ReceiverAdded, ReceiverNotAdded {
try { try {
const stack: FixedArray = LoadJoinStack() const stack: FixedArray = LoadJoinStack()
otherwise IfUninitialized; otherwise IfUninitialized;
...@@ -477,7 +471,7 @@ namespace array_join { ...@@ -477,7 +471,7 @@ namespace array_join {
stack.objects[0] = receiver; stack.objects[0] = receiver;
} else if (JoinStackPush(stack, receiver) == False) } else if (JoinStackPush(stack, receiver) == False)
deferred { deferred {
goto ReceiverNotAdded; return false;
} }
} }
label IfUninitialized { label IfUninitialized {
...@@ -486,7 +480,7 @@ namespace array_join { ...@@ -486,7 +480,7 @@ namespace array_join {
stack.objects[0] = receiver; stack.objects[0] = receiver;
SetJoinStack(stack); SetJoinStack(stack);
} }
goto ReceiverAdded; return true;
} }
// Removes a receiver from the stack. The FixedArray will automatically shrink // Removes a receiver from the stack. The FixedArray will automatically shrink
......
...@@ -1632,26 +1632,33 @@ extern operator '<' macro Float64LessThan(float64, float64): bool; ...@@ -1632,26 +1632,33 @@ extern operator '<' macro Float64LessThan(float64, float64): bool;
extern macro BranchIfNumberEqual(Number, Number): never extern macro BranchIfNumberEqual(Number, Number): never
labels Taken, NotTaken; labels Taken, NotTaken;
operator '==' macro IsNumberEqual(a: Number, b: Number): bool { operator '==' macro IsNumberEqual(a: Number, b: Number): bool {
return (BranchIfNumberEqual(a, b)) ? true : false; BranchIfNumberEqual(a, b) otherwise return true, return false;
} }
operator '!=' macro IsNumberNotEqual(a: Number, b: Number): bool { operator '!=' macro IsNumberNotEqual(a: Number, b: Number): bool {
return (BranchIfNumberEqual(a, b)) ? false : true; return !(a == b);
} }
extern operator '<' macro BranchIfNumberLessThan(Number, Number): never extern macro BranchIfNumberLessThan(Number, Number): never
labels Taken, NotTaken; labels Taken, NotTaken;
extern operator '<=' macro BranchIfNumberLessThanOrEqual(Number, Number): never operator '<' macro NumberIsLessThan(a: Number, b: Number): bool {
BranchIfNumberLessThan(a, b) otherwise return true, return false;
}
extern macro BranchIfNumberLessThanOrEqual(Number, Number): never
labels Taken, NotTaken; labels Taken, NotTaken;
operator '<=' macro NumberIsLessThanOrEqual(a: Number, b: Number): bool {
BranchIfNumberLessThanOrEqual(a, b) otherwise return true, return false;
}
extern operator '>' macro BranchIfNumberGreaterThan(Number, Number): never operator '>' macro NumberIsGreaterThan(a: Number, b: Number): bool {
labels Taken, NotTaken; return b < a;
extern operator '>=' macro BranchIfNumberGreaterThanOrEqual( }
Number, Number): never operator '>=' macro NumberIsGreaterThanOrEqual(a: Number, b: Number): bool {
labels Taken, NotTaken; return b <= a;
}
extern macro BranchIfFloat64IsNaN(float64): never extern macro BranchIfFloat64IsNaN(float64): never
labels Taken, NotTaken; labels Taken, NotTaken;
macro Float64IsNaN(n: float64): bool { macro Float64IsNaN(n: float64): bool {
return (BranchIfFloat64IsNaN(n)) ? true : false; BranchIfFloat64IsNaN(n) otherwise return true, return false;
} }
// The type of all tagged values that can safely be compared with WordEqual. // The type of all tagged values that can safely be compared with WordEqual.
...@@ -2020,7 +2027,7 @@ Cast<FastJSRegExp>(implicit context: Context)(o: HeapObject): FastJSRegExp ...@@ -2020,7 +2027,7 @@ Cast<FastJSRegExp>(implicit context: Context)(o: HeapObject): FastJSRegExp
// the conditions to make a regexp object fast differ based on the callsite. // the conditions to make a regexp object fast differ based on the callsite.
// For now, run the strict variant since replace (the only current callsite) // For now, run the strict variant since replace (the only current callsite)
// accesses flag getters. // accesses flag getters.
if (regexp::BranchIfFastRegExp_Strict(o)) { if (regexp::IsFastRegExpStrict(o)) {
return %RawDownCast<FastJSRegExp>(o); return %RawDownCast<FastJSRegExp>(o);
} }
goto CastError; goto CastError;
...@@ -2392,20 +2399,9 @@ Convert<bint, Smi>(v: Smi): bint { ...@@ -2392,20 +2399,9 @@ Convert<bint, Smi>(v: Smi): bint {
return SmiToBInt(v); return SmiToBInt(v);
} }
macro BranchIf<A: type, B: type>(implicit context: Context)(o: B): never
labels True, False {
Cast<A>(o) otherwise False;
goto True;
}
macro BranchIfNot<A: type, B: type>(implicit context: Context)(o: B): never
labels True, False {
Cast<A>(o) otherwise True;
goto False;
}
macro Is<A: type, B: type>(implicit context: Context)(o: B): bool { macro Is<A: type, B: type>(implicit context: Context)(o: B): bool {
return (BranchIf<A, B>(o)) ? true : false; Cast<A>(o) otherwise return false;
return true;
} }
macro UnsafeCast<A: type>(implicit context: Context)(o: Object): A { macro UnsafeCast<A: type>(implicit context: Context)(o: Object): A {
...@@ -2918,17 +2914,18 @@ macro NumberIsNaN(number: Number): bool { ...@@ -2918,17 +2914,18 @@ macro NumberIsNaN(number: Number): bool {
} }
extern macro GotoIfForceSlowPath() labels Taken; extern macro GotoIfForceSlowPath() labels Taken;
macro IsForceSlowPath(): bool {
GotoIfForceSlowPath() otherwise return true;
return false;
}
extern macro BranchIfToBooleanIsTrue(Object): never extern macro BranchIfToBooleanIsTrue(Object): never
labels Taken, NotTaken; labels Taken, NotTaken;
extern macro BranchIfToBooleanIsFalse(Object): never extern macro BranchIfToBooleanIsFalse(Object): never
labels Taken, NotTaken; labels Taken, NotTaken;
macro ToBoolean(obj: Object): bool { macro ToBoolean(obj: Object): bool {
if (BranchIfToBooleanIsTrue(obj)) { BranchIfToBooleanIsTrue(obj) otherwise return true, return false;
return true;
} else {
return false;
}
} }
@export @export
...@@ -2941,6 +2938,9 @@ macro RequireObjectCoercible(implicit context: Context)( ...@@ -2941,6 +2938,9 @@ macro RequireObjectCoercible(implicit context: Context)(
} }
extern macro BranchIfSameValue(Object, Object): never labels Taken, NotTaken; extern macro BranchIfSameValue(Object, Object): never labels Taken, NotTaken;
macro SameValue(a: Object, b: Object): bool {
BranchIfSameValue(a, b) otherwise return true, return false;
}
transitioning macro ToIndex(input: Object, context: Context): Number transitioning macro ToIndex(input: Object, context: Context): Number
labels RangeError { labels RangeError {
...@@ -3005,25 +3005,20 @@ struct KeyValuePair { ...@@ -3005,25 +3005,20 @@ struct KeyValuePair {
// using "legacy" APIs. In Torque code, these should not be used. // using "legacy" APIs. In Torque code, these should not be used.
@export @export
macro IsFastJSArray(o: Object, context: Context): bool { macro IsFastJSArray(o: Object, context: Context): bool {
try { // Long-term, it's likely not a good idea to have this slow-path test here,
// Long-term, it's likely not a good idea to have this slow-path test here, // since it fundamentally breaks the type system.
// since it fundamentally breaks the type system. if (IsForceSlowPath()) return false;
GotoIfForceSlowPath() otherwise ForceSlow;
}
label ForceSlow {
return false;
}
return Is<FastJSArray>(o); return Is<FastJSArray>(o);
} }
@export @export
macro BranchIfFastJSArray(o: Object, context: Context): never labels True, macro BranchIfFastJSArray(o: Object, context: Context): never labels True,
False { False {
// Long-term, it's likely not a good idea to have this slow-path test here, if (IsFastJSArray(o, context)) {
// since it fundamentally breaks the type system. goto True;
GotoIfForceSlowPath() otherwise False; } else {
BranchIf<FastJSArray>(o) otherwise True, False; goto False;
}
} }
@export @export
...@@ -3031,8 +3026,12 @@ macro BranchIfFastJSArrayForRead(o: Object, context: Context): ...@@ -3031,8 +3026,12 @@ macro BranchIfFastJSArrayForRead(o: Object, context: Context):
never labels True, False { never labels True, False {
// Long-term, it's likely not a good idea to have this slow-path test here, // Long-term, it's likely not a good idea to have this slow-path test here,
// since it fundamentally breaks the type system. // since it fundamentally breaks the type system.
GotoIfForceSlowPath() otherwise False; if (IsForceSlowPath()) goto False;
BranchIf<FastJSArrayForRead>(o) otherwise True, False; if (Is<FastJSArrayForRead>(o)) {
goto True;
} else {
goto False;
}
} }
@export @export
......
...@@ -40,7 +40,7 @@ namespace proxy { ...@@ -40,7 +40,7 @@ namespace proxy {
const trapResult = Call(context, trap, handler, target, name); const trapResult = Call(context, trap, handler, target, name);
// 9. If booleanTrapResult is false, return false. // 9. If booleanTrapResult is false, return false.
if (BranchIfToBooleanIsFalse(trapResult)) { if (!ToBoolean(trapResult)) {
if (languageMode == SmiConstant(kStrict)) { if (languageMode == SmiConstant(kStrict)) {
ThrowTypeError(kProxyTrapReturnedFalsishFor, kTrapName, name); ThrowTypeError(kProxyTrapReturnedFalsishFor, kTrapName, name);
} }
......
...@@ -51,7 +51,7 @@ namespace proxy { ...@@ -51,7 +51,7 @@ namespace proxy {
// 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError
// exception. // exception.
// 13. Return handlerProto. // 13. Return handlerProto.
if (BranchIfSameValue(targetProto, handlerProto)) { if (SameValue(targetProto, handlerProto)) {
return handlerProto; return handlerProto;
} }
ThrowTypeError(kProxyGetPrototypeOfNonExtensible); ThrowTypeError(kProxyGetPrototypeOfNonExtensible);
......
...@@ -40,7 +40,7 @@ namespace proxy { ...@@ -40,7 +40,7 @@ namespace proxy {
// CheckHasTrapResult). // CheckHasTrapResult).
// 10. Return booleanTrapResult. // 10. Return booleanTrapResult.
const trapResult = Call(context, trap, handler, target, name); const trapResult = Call(context, trap, handler, target, name);
if (BranchIfToBooleanIsTrue(trapResult)) { if (ToBoolean(trapResult)) {
return True; return True;
} }
CheckHasTrapResult(target, proxy, name); CheckHasTrapResult(target, proxy, name);
......
...@@ -36,7 +36,7 @@ namespace proxy { ...@@ -36,7 +36,7 @@ namespace proxy {
// 8. If booleanTrapResult is true, then // 8. If booleanTrapResult is true, then
// 8.a. Let extensibleTarget be ? IsExtensible(target). // 8.a. Let extensibleTarget be ? IsExtensible(target).
// 8.b If extensibleTarget is true, throw a TypeError exception. // 8.b If extensibleTarget is true, throw a TypeError exception.
if (BranchIfToBooleanIsTrue(trapResult)) { if (ToBoolean(trapResult)) {
const extensibleTarget: Object = object::ObjectIsExtensible(target); const extensibleTarget: Object = object::ObjectIsExtensible(target);
assert(extensibleTarget == True || extensibleTarget == False); assert(extensibleTarget == True || extensibleTarget == False);
if (extensibleTarget == True) { if (extensibleTarget == True) {
......
...@@ -62,7 +62,7 @@ namespace proxy { ...@@ -62,7 +62,7 @@ namespace proxy {
// 12. Return true. // 12. Return true.
const trapResult = const trapResult =
Call(context, trap, handler, target, name, value, receiverValue); Call(context, trap, handler, target, name, value, receiverValue);
if (BranchIfToBooleanIsTrue(trapResult)) { if (ToBoolean(trapResult)) {
CheckGetSetTrapResult(target, proxy, name, value, kProxySet); CheckGetSetTrapResult(target, proxy, name, value, kProxySet);
return value; return value;
} }
......
...@@ -37,7 +37,7 @@ namespace proxy { ...@@ -37,7 +37,7 @@ namespace proxy {
const trapResult = Call(context, trap, handler, target, proto); const trapResult = Call(context, trap, handler, target, proto);
// 9. If booleanTrapResult is false, return false. // 9. If booleanTrapResult is false, return false.
if (BranchIfToBooleanIsFalse(trapResult)) { if (!ToBoolean(trapResult)) {
if (doThrow == True) { if (doThrow == True) {
ThrowTypeError(kProxyTrapReturnedFalsishFor, kTrapName); ThrowTypeError(kProxyTrapReturnedFalsishFor, kTrapName);
} }
...@@ -58,7 +58,7 @@ namespace proxy { ...@@ -58,7 +58,7 @@ namespace proxy {
// 13. If SameValue(V, targetProto) is false, throw a TypeError // 13. If SameValue(V, targetProto) is false, throw a TypeError
// exception. // exception.
// 14. Return true. // 14. Return true.
if (BranchIfSameValue(proto, targetProto)) { if (SameValue(proto, targetProto)) {
return True; return True;
} }
ThrowTypeError(kProxySetPrototypeOfNonExtensible); ThrowTypeError(kProxySetPrototypeOfNonExtensible);
......
...@@ -9,5 +9,8 @@ namespace regexp { ...@@ -9,5 +9,8 @@ namespace regexp {
extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp_Strict( extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp_Strict(
implicit context: Context)(HeapObject): never labels IsFast, implicit context: Context)(HeapObject): never labels IsFast,
IsSlow; IsSlow;
macro IsFastRegExpStrict(implicit context: Context)(o: HeapObject): bool {
BranchIfFastRegExp_Strict(o) otherwise return true, return false;
}
} }
...@@ -53,7 +53,7 @@ namespace typed_array_filter { ...@@ -53,7 +53,7 @@ namespace typed_array_filter {
// d. If selected is true, then // d. If selected is true, then
// i. Append kValue to the end of kept. // i. Append kValue to the end of kept.
// ii. Increase captured by 1. // ii. Increase captured by 1.
if (BranchIfToBooleanIsTrue(selected)) kept.Push(value); if (ToBoolean(selected)) kept.Push(value);
// e.Increase k by 1. // e.Increase k by 1.
} }
......
...@@ -13,7 +13,7 @@ namespace typed_array_slice { ...@@ -13,7 +13,7 @@ namespace typed_array_slice {
macro FastCopy( macro FastCopy(
src: typed_array::AttachedJSTypedArray, dest: JSTypedArray, k: intptr, src: typed_array::AttachedJSTypedArray, dest: JSTypedArray, k: intptr,
count: PositiveSmi) labels IfSlow { count: PositiveSmi) labels IfSlow {
GotoIfForceSlowPath() otherwise IfSlow; if (IsForceSlowPath()) goto IfSlow;
const srcKind: ElementsKind = src.elements_kind; const srcKind: ElementsKind = src.elements_kind;
const destInfo = typed_array::GetTypedArrayElementsInfo(dest); const destInfo = typed_array::GetTypedArrayElementsInfo(dest);
......
...@@ -15,8 +15,6 @@ namespace internal { ...@@ -15,8 +15,6 @@ namespace internal {
namespace torque { namespace torque {
static constexpr const char* const kFromConstexprMacroName = "FromConstexpr"; static constexpr const char* const kFromConstexprMacroName = "FromConstexpr";
static constexpr const char* kTrueLabelName = "__True";
static constexpr const char* kFalseLabelName = "__False";
static constexpr const char* kMacroEndLabelName = "__macro_end"; static constexpr const char* kMacroEndLabelName = "__macro_end";
static constexpr const char* kBreakLabelName = "__break"; static constexpr const char* kBreakLabelName = "__break";
static constexpr const char* kContinueLabelName = "__continue"; static constexpr const char* kContinueLabelName = "__continue";
......
...@@ -647,24 +647,8 @@ VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) { ...@@ -647,24 +647,8 @@ VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
} }
VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) { VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
VisitResult left_result; StackScope outer_scope(this);
{ VisitResult left_result = Visit(expr->left);
Block* false_block = assembler().NewBlock(assembler().CurrentStack());
Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
kFalseLabelName, LocalLabel{false_block}};
left_result = Visit(expr->left);
if (left_result.type()->IsBool()) {
Block* true_block = LookupSimpleLabel(kTrueLabelName);
assembler().Branch(true_block, false_block);
assembler().Bind(false_block);
} else if (left_result.type()->IsNever()) {
assembler().Bind(false_block);
} else if (!left_result.type()->IsConstexprBool()) {
ReportError(
"expected type bool, constexpr bool, or never on left-hand side of "
"operator ||");
}
}
if (left_result.type()->IsConstexprBool()) { if (left_result.type()->IsConstexprBool()) {
VisitResult right_result = Visit(expr->right); VisitResult right_result = Visit(expr->right);
...@@ -678,38 +662,34 @@ VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) { ...@@ -678,38 +662,34 @@ VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
" || " + right_result.constexpr_value() + ")"); " || " + right_result.constexpr_value() + ")");
} }
VisitResult right_result = Visit(expr->right); Block* true_block = assembler().NewBlock();
if (right_result.type()->IsBool()) { Block* false_block = assembler().NewBlock();
Block* true_block = LookupSimpleLabel(kTrueLabelName); Block* done_block = assembler().NewBlock();
Block* false_block = LookupSimpleLabel(kFalseLabelName);
assembler().Branch(true_block, false_block); left_result = GenerateImplicitConvert(TypeOracle::GetBoolType(), left_result);
return VisitResult::NeverResult(); GenerateBranch(left_result, true_block, false_block);
} else if (!right_result.type()->IsNever()) {
ReportError( assembler().Bind(true_block);
"expected type bool or never on right-hand side of operator ||"); VisitResult true_result = GenerateBoolConstant(true);
assembler().Goto(done_block);
assembler().Bind(false_block);
VisitResult false_result;
{
StackScope false_block_scope(this);
false_result = false_block_scope.Yield(
GenerateImplicitConvert(TypeOracle::GetBoolType(), Visit(expr->right)));
} }
return right_result; assembler().Goto(done_block);
assembler().Bind(done_block);
DCHECK_EQ(true_result, false_result);
return outer_scope.Yield(true_result);
} }
VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) { VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
VisitResult left_result; StackScope outer_scope(this);
{ VisitResult left_result = Visit(expr->left);
Block* true_block = assembler().NewBlock(assembler().CurrentStack());
Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
kTrueLabelName, LocalLabel{true_block}};
left_result = Visit(expr->left);
if (left_result.type()->IsBool()) {
Block* false_block = LookupSimpleLabel(kFalseLabelName);
assembler().Branch(true_block, false_block);
assembler().Bind(true_block);
} else if (left_result.type()->IsNever()) {
assembler().Bind(true_block);
} else if (!left_result.type()->IsConstexprBool()) {
ReportError(
"expected type bool, constexpr bool, or never on left-hand side of "
"operator &&");
}
}
if (left_result.type()->IsConstexprBool()) { if (left_result.type()->IsConstexprBool()) {
VisitResult right_result = Visit(expr->right); VisitResult right_result = Visit(expr->right);
...@@ -723,17 +703,29 @@ VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) { ...@@ -723,17 +703,29 @@ VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
" && " + right_result.constexpr_value() + ")"); " && " + right_result.constexpr_value() + ")");
} }
VisitResult right_result = Visit(expr->right); Block* true_block = assembler().NewBlock();
if (right_result.type()->IsBool()) { Block* false_block = assembler().NewBlock();
Block* true_block = LookupSimpleLabel(kTrueLabelName); Block* done_block = assembler().NewBlock();
Block* false_block = LookupSimpleLabel(kFalseLabelName);
assembler().Branch(true_block, false_block); left_result = GenerateImplicitConvert(TypeOracle::GetBoolType(), left_result);
return VisitResult::NeverResult(); GenerateBranch(left_result, true_block, false_block);
} else if (!right_result.type()->IsNever()) {
ReportError( assembler().Bind(true_block);
"expected type bool or never on right-hand side of operator &&"); VisitResult true_result;
{
StackScope true_block_scope(this);
true_result = true_block_scope.Yield(
GenerateImplicitConvert(TypeOracle::GetBoolType(), Visit(expr->right)));
} }
return right_result; assembler().Goto(done_block);
assembler().Bind(false_block);
VisitResult false_result = GenerateBoolConstant(false);
assembler().Goto(done_block);
assembler().Bind(done_block);
DCHECK_EQ(true_result, false_result);
return outer_scope.Yield(true_result);
} }
VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) { VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
...@@ -1661,11 +1653,7 @@ Callable* ImplementationVisitor::LookupCallable( ...@@ -1661,11 +1653,7 @@ Callable* ImplementationVisitor::LookupCallable(
std::vector<size_t> candidates; std::vector<size_t> candidates;
for (size_t i = 0; i < overloads.size(); ++i) { for (size_t i = 0; i < overloads.size(); ++i) {
const Signature& signature = overload_signatures[i]; const Signature& signature = overload_signatures[i];
bool try_bool_context = labels.size() == 0 && if (IsCompatibleSignature(signature, parameter_types, labels.size())) {
signature.return_type == TypeOracle::GetNeverType();
if (IsCompatibleSignature(signature, parameter_types, labels.size()) ||
(try_bool_context &&
IsCompatibleSignature(signature, parameter_types, 2))) {
candidates.push_back(i); candidates.push_back(i);
} }
} }
...@@ -2099,25 +2087,6 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -2099,25 +2087,6 @@ VisitResult ImplementationVisitor::GenerateCall(
Callable* callable, base::Optional<LocationReference> this_reference, Callable* callable, base::Optional<LocationReference> this_reference,
Arguments arguments, const TypeVector& specialization_types, Arguments arguments, const TypeVector& specialization_types,
bool is_tailcall) { bool is_tailcall) {
// Operators used in a branching context can also be function calls that never
// return but have a True and False label
if (arguments.labels.size() == 0 &&
callable->signature().labels.size() == 2) {
base::Optional<Binding<LocalLabel>*> true_label =
TryLookupLabel(kTrueLabelName);
base::Optional<Binding<LocalLabel>*> false_label =
TryLookupLabel(kFalseLabelName);
if (!true_label || !false_label) {
ReportError(
callable->ReadableName(),
" does not return a value, but has to be called in a branching "
"context (e.g., conditional or if-condition). You can fix this by "
"adding \"? true : false\".");
}
arguments.labels.push_back(*true_label);
arguments.labels.push_back(*false_label);
}
const Type* return_type = callable->signature().return_type; const Type* return_type = callable->signature().return_type;
if (is_tailcall) { if (is_tailcall) {
...@@ -2454,32 +2423,20 @@ void ImplementationVisitor::GenerateBranch(const VisitResult& condition, ...@@ -2454,32 +2423,20 @@ void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
assembler().Branch(true_block, false_block); assembler().Branch(true_block, false_block);
} }
void ImplementationVisitor::GenerateExpressionBranch( VisitResult ImplementationVisitor::GenerateBoolConstant(bool constant) {
VisitResultGenerator generator, Block* true_block, Block* false_block) { return GenerateImplicitConvert(TypeOracle::GetBoolType(),
// Conditional expressions can either explicitly return a bit VisitResult(TypeOracle::GetConstexprBoolType(),
// type, or they can be backed by macros that don't return but constant ? "true" : "false"));
// take a true and false label. By declaring the labels before
// visiting the conditional expression, those label-based
// macro conditionals will be able to find them through normal
// label lookups.
Binding<LocalLabel> true_binding{&LabelBindingsManager::Get(), kTrueLabelName,
LocalLabel{true_block}};
Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
kFalseLabelName, LocalLabel{false_block}};
StackScope stack_scope(this);
VisitResult expression_result = generator();
if (!expression_result.type()->IsNever()) {
expression_result = stack_scope.Yield(
GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
GenerateBranch(expression_result, true_block, false_block);
}
} }
void ImplementationVisitor::GenerateExpressionBranch(Expression* expression, void ImplementationVisitor::GenerateExpressionBranch(Expression* expression,
Block* true_block, Block* true_block,
Block* false_block) { Block* false_block) {
GenerateExpressionBranch([&]() { return this->Visit(expression); }, StackScope stack_scope(this);
true_block, false_block); VisitResult expression_result = this->Visit(expression);
expression_result = stack_scope.Yield(
GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
GenerateBranch(expression_result, true_block, false_block);
} }
VisitResult ImplementationVisitor::GenerateImplicitConvert( VisitResult ImplementationVisitor::GenerateImplicitConvert(
......
...@@ -611,9 +611,8 @@ class ImplementationVisitor { ...@@ -611,9 +611,8 @@ class ImplementationVisitor {
void GenerateBranch(const VisitResult& condition, Block* true_block, void GenerateBranch(const VisitResult& condition, Block* true_block,
Block* false_block); Block* false_block);
using VisitResultGenerator = std::function<VisitResult()>; VisitResult GenerateBoolConstant(bool constant);
void GenerateExpressionBranch(VisitResultGenerator, Block* true_block,
Block* false_block);
void GenerateExpressionBranch(Expression* expression, Block* true_block, void GenerateExpressionBranch(Expression* expression, Block* true_block,
Block* false_block); Block* false_block);
......
...@@ -543,95 +543,34 @@ namespace test { ...@@ -543,95 +543,34 @@ namespace test {
check(equal); check(equal);
} }
macro BoolToBranch(x: bool): never
labels Taken, NotTaken {
if (x) {
goto Taken;
} else {
goto NotTaken;
}
}
@export
macro TestOrAnd1(x: bool, y: bool, z: bool): bool {
return BoolToBranch(x) || y && z ? true : false;
}
@export
macro TestOrAnd2(x: bool, y: bool, z: bool): bool {
return x || BoolToBranch(y) && z ? true : false;
}
@export
macro TestOrAnd3(x: bool, y: bool, z: bool): bool {
return x || y && BoolToBranch(z) ? true : false;
}
@export
macro TestAndOr1(x: bool, y: bool, z: bool): bool {
return BoolToBranch(x) && y || z ? true : false;
}
@export @export
macro TestAndOr2(x: bool, y: bool, z: bool): bool { macro TestOrAnd(x: bool, y: bool, z: bool): bool {
return x && BoolToBranch(y) || z ? true : false; return x || y && z ? true : false;
} }
@export @export
macro TestAndOr3(x: bool, y: bool, z: bool): bool { macro TestAndOr(x: bool, y: bool, z: bool): bool {
return x && y || BoolToBranch(z) ? true : false; return x && y || z ? true : false;
} }
@export @export
macro TestLogicalOperators() { macro TestLogicalOperators() {
check(TestAndOr1(true, true, true)); check(TestAndOr(true, true, true));
check(TestAndOr2(true, true, true)); check(TestAndOr(true, true, false));
check(TestAndOr3(true, true, true)); check(TestAndOr(true, false, true));
check(TestAndOr1(true, true, false)); check(!TestAndOr(true, false, false));
check(TestAndOr2(true, true, false)); check(TestAndOr(false, true, true));
check(TestAndOr3(true, true, false)); check(!TestAndOr(false, true, false));
check(TestAndOr1(true, false, true)); check(TestAndOr(false, false, true));
check(TestAndOr2(true, false, true)); check(!TestAndOr(false, false, false));
check(TestAndOr3(true, false, true)); check(TestOrAnd(true, true, true));
check(!TestAndOr1(true, false, false)); check(TestOrAnd(true, true, false));
check(!TestAndOr2(true, false, false)); check(TestOrAnd(true, false, true));
check(!TestAndOr3(true, false, false)); check(TestOrAnd(true, false, false));
check(TestAndOr1(false, true, true)); check(TestOrAnd(false, true, true));
check(TestAndOr2(false, true, true)); check(!TestOrAnd(false, true, false));
check(TestAndOr3(false, true, true)); check(!TestOrAnd(false, false, true));
check(!TestAndOr1(false, true, false)); check(!TestOrAnd(false, false, false));
check(!TestAndOr2(false, true, false));
check(!TestAndOr3(false, true, false));
check(TestAndOr1(false, false, true));
check(TestAndOr2(false, false, true));
check(TestAndOr3(false, false, true));
check(!TestAndOr1(false, false, false));
check(!TestAndOr2(false, false, false));
check(!TestAndOr3(false, false, false));
check(TestOrAnd1(true, true, true));
check(TestOrAnd2(true, true, true));
check(TestOrAnd3(true, true, true));
check(TestOrAnd1(true, true, false));
check(TestOrAnd2(true, true, false));
check(TestOrAnd3(true, true, false));
check(TestOrAnd1(true, false, true));
check(TestOrAnd2(true, false, true));
check(TestOrAnd3(true, false, true));
check(TestOrAnd1(true, false, false));
check(TestOrAnd2(true, false, false));
check(TestOrAnd3(true, false, false));
check(TestOrAnd1(false, true, true));
check(TestOrAnd2(false, true, true));
check(TestOrAnd3(false, true, true));
check(!TestOrAnd1(false, true, false));
check(!TestOrAnd2(false, true, false));
check(!TestOrAnd3(false, true, false));
check(!TestOrAnd1(false, false, true));
check(!TestOrAnd2(false, false, true));
check(!TestOrAnd3(false, false, true));
check(!TestOrAnd1(false, false, false));
check(!TestOrAnd2(false, false, false));
check(!TestOrAnd3(false, false, false));
} }
@export @export
......
...@@ -143,7 +143,7 @@ namespace array { ...@@ -143,7 +143,7 @@ namespace array {
let canUseSameAccessorFn: CanUseSameAccessorFn; let canUseSameAccessorFn: CanUseSameAccessorFn;
try { try {
GotoIfForceSlowPath() otherwise Slow; if (IsForceSlowPath()) goto Slow;
const a: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow; const a: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
// Copy copy-on-write (COW) arrays. // Copy copy-on-write (COW) arrays.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment