Commit b95def34 authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[torque] Add local const bindings

This CL adds local const bindings. This means that instead of
generating TVARIABLEs for variables, we can generate simple TNodes.

Example:

macro FooBar(): {
  const kSomeSmi: Smi = 10;
  ...
}

This CL also enforces that variables with a constexpr type are bound
using 'const' and not 'let'.

R=tebbi@chromium.org

Bug: v8:7793
Change-Id: Id20a18149df9fc374ce718bdb1478e3eabb6e6df
Reviewed-on: https://chromium-review.googlesource.com/1138316
Commit-Queue: Simon Zünd <szuend@google.com>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54479}
parent aab1d29d
...@@ -31,6 +31,7 @@ TAIL: 'tail'; ...@@ -31,6 +31,7 @@ TAIL: 'tail';
ISNT: 'isnt'; ISNT: 'isnt';
IS: 'is'; IS: 'is';
LET: 'let'; LET: 'let';
CONST: 'const';
EXTERN: 'extern'; EXTERN: 'extern';
ASSERT_TOKEN: 'assert'; ASSERT_TOKEN: 'assert';
CHECK_TOKEN: 'check'; CHECK_TOKEN: 'check';
...@@ -227,7 +228,7 @@ argumentList: '(' argument? (',' argument)* ')'; ...@@ -227,7 +228,7 @@ argumentList: '(' argument? (',' argument)* ')';
helperCall: (MIN | MAX | IDENTIFIER) genericSpecializationTypeList? argumentList optionalOtherwise; helperCall: (MIN | MAX | IDENTIFIER) genericSpecializationTypeList? argumentList optionalOtherwise;
labelReference: IDENTIFIER; labelReference: IDENTIFIER;
variableDeclaration: LET IDENTIFIER ':' type; variableDeclaration: (LET | CONST) IDENTIFIER ':' type;
variableDeclarationWithInitialization: variableDeclaration (ASSIGNMENT expression)?; variableDeclarationWithInitialization: variableDeclaration (ASSIGNMENT expression)?;
helperCallStatement: (TAIL)? helperCall; helperCallStatement: (TAIL)? helperCall;
expressionStatement: assignment; expressionStatement: assignment;
...@@ -277,8 +278,8 @@ externalRuntime : EXTERN RUNTIME IDENTIFIER typeListMaybeVarArgs optionalType '; ...@@ -277,8 +278,8 @@ externalRuntime : EXTERN RUNTIME IDENTIFIER typeListMaybeVarArgs optionalType ';
builtinDeclaration : JAVASCRIPT? BUILTIN IDENTIFIER optionalGenericTypeList parameterList optionalType (helperBody | ';'); builtinDeclaration : JAVASCRIPT? BUILTIN IDENTIFIER optionalGenericTypeList parameterList optionalType (helperBody | ';');
genericSpecialization: IDENTIFIER genericSpecializationTypeList parameterList optionalType optionalLabelList helperBody; genericSpecialization: IDENTIFIER genericSpecializationTypeList parameterList optionalType optionalLabelList helperBody;
macroDeclaration : ('operator' STRING_LITERAL)? MACRO IDENTIFIER optionalGenericTypeList parameterList optionalType optionalLabelList (helperBody | ';'); macroDeclaration : ('operator' STRING_LITERAL)? MACRO IDENTIFIER optionalGenericTypeList parameterList optionalType optionalLabelList (helperBody | ';');
externConstDeclaration : 'const' IDENTIFIER ':' type generatesDeclaration ';'; externConstDeclaration : CONST IDENTIFIER ':' type generatesDeclaration ';';
constDeclaration: 'const' IDENTIFIER ':' type ASSIGNMENT expression ';'; constDeclaration: CONST IDENTIFIER ':' type ASSIGNMENT expression ';';
declaration declaration
: typeDeclaration : typeDeclaration
......
This diff is collapsed.
...@@ -33,29 +33,29 @@ class TorqueLexer : public antlr4::Lexer { ...@@ -33,29 +33,29 @@ class TorqueLexer : public antlr4::Lexer {
T__17 = 18, T__17 = 18,
T__18 = 19, T__18 = 19,
T__19 = 20, T__19 = 20,
T__20 = 21, MACRO = 21,
MACRO = 22, BUILTIN = 22,
BUILTIN = 23, RUNTIME = 23,
RUNTIME = 24, MODULE = 24,
MODULE = 25, JAVASCRIPT = 25,
JAVASCRIPT = 26, DEFERRED = 26,
DEFERRED = 27, IF = 27,
IF = 28, FOR = 28,
FOR = 29, WHILE = 29,
WHILE = 30, RETURN = 30,
RETURN = 31, CONSTEXPR = 31,
CONSTEXPR = 32, CONTINUE = 32,
CONTINUE = 33, BREAK = 33,
BREAK = 34, GOTO = 34,
GOTO = 35, OTHERWISE = 35,
OTHERWISE = 36, TRY = 36,
TRY = 37, LABEL = 37,
LABEL = 38, LABELS = 38,
LABELS = 39, TAIL = 39,
TAIL = 40, ISNT = 40,
ISNT = 41, IS = 41,
IS = 42, LET = 42,
LET = 43, CONST = 43,
EXTERN = 44, EXTERN = 44,
ASSERT_TOKEN = 45, ASSERT_TOKEN = 45,
CHECK_TOKEN = 46, CHECK_TOKEN = 46,
......
This diff is collapsed.
...@@ -33,29 +33,29 @@ class TorqueParser : public antlr4::Parser { ...@@ -33,29 +33,29 @@ class TorqueParser : public antlr4::Parser {
T__17 = 18, T__17 = 18,
T__18 = 19, T__18 = 19,
T__19 = 20, T__19 = 20,
T__20 = 21, MACRO = 21,
MACRO = 22, BUILTIN = 22,
BUILTIN = 23, RUNTIME = 23,
RUNTIME = 24, MODULE = 24,
MODULE = 25, JAVASCRIPT = 25,
JAVASCRIPT = 26, DEFERRED = 26,
DEFERRED = 27, IF = 27,
IF = 28, FOR = 28,
FOR = 29, WHILE = 29,
WHILE = 30, RETURN = 30,
RETURN = 31, CONSTEXPR = 31,
CONSTEXPR = 32, CONTINUE = 32,
CONTINUE = 33, BREAK = 33,
BREAK = 34, GOTO = 34,
GOTO = 35, OTHERWISE = 35,
OTHERWISE = 36, TRY = 36,
TRY = 37, LABEL = 37,
LABEL = 38, LABELS = 38,
LABELS = 39, TAIL = 39,
TAIL = 40, ISNT = 40,
ISNT = 41, IS = 41,
IS = 42, LET = 42,
LET = 43, CONST = 43,
EXTERN = 44, EXTERN = 44,
ASSERT_TOKEN = 45, ASSERT_TOKEN = 45,
CHECK_TOKEN = 46, CHECK_TOKEN = 46,
...@@ -893,9 +893,10 @@ class TorqueParser : public antlr4::Parser { ...@@ -893,9 +893,10 @@ class TorqueParser : public antlr4::Parser {
VariableDeclarationContext(antlr4::ParserRuleContext* parent, VariableDeclarationContext(antlr4::ParserRuleContext* parent,
size_t invokingState); size_t invokingState);
size_t getRuleIndex() const override; size_t getRuleIndex() const override;
antlr4::tree::TerminalNode* LET();
antlr4::tree::TerminalNode* IDENTIFIER(); antlr4::tree::TerminalNode* IDENTIFIER();
TypeContext* type(); TypeContext* type();
antlr4::tree::TerminalNode* LET();
antlr4::tree::TerminalNode* CONST();
void enterRule(antlr4::tree::ParseTreeListener* listener) override; void enterRule(antlr4::tree::ParseTreeListener* listener) override;
void exitRule(antlr4::tree::ParseTreeListener* listener) override; void exitRule(antlr4::tree::ParseTreeListener* listener) override;
...@@ -1404,6 +1405,7 @@ class TorqueParser : public antlr4::Parser { ...@@ -1404,6 +1405,7 @@ class TorqueParser : public antlr4::Parser {
ExternConstDeclarationContext(antlr4::ParserRuleContext* parent, ExternConstDeclarationContext(antlr4::ParserRuleContext* parent,
size_t invokingState); size_t invokingState);
size_t getRuleIndex() const override; size_t getRuleIndex() const override;
antlr4::tree::TerminalNode* CONST();
antlr4::tree::TerminalNode* IDENTIFIER(); antlr4::tree::TerminalNode* IDENTIFIER();
TypeContext* type(); TypeContext* type();
GeneratesDeclarationContext* generatesDeclaration(); GeneratesDeclarationContext* generatesDeclaration();
...@@ -1421,6 +1423,7 @@ class TorqueParser : public antlr4::Parser { ...@@ -1421,6 +1423,7 @@ class TorqueParser : public antlr4::Parser {
ConstDeclarationContext(antlr4::ParserRuleContext* parent, ConstDeclarationContext(antlr4::ParserRuleContext* parent,
size_t invokingState); size_t invokingState);
size_t getRuleIndex() const override; size_t getRuleIndex() const override;
antlr4::tree::TerminalNode* CONST();
antlr4::tree::TerminalNode* IDENTIFIER(); antlr4::tree::TerminalNode* IDENTIFIER();
TypeContext* type(); TypeContext* type();
antlr4::tree::TerminalNode* ASSIGNMENT(); antlr4::tree::TerminalNode* ASSIGNMENT();
......
...@@ -345,8 +345,10 @@ antlrcpp::Any AstGenerator::visitTypeAliasDeclaration( ...@@ -345,8 +345,10 @@ antlrcpp::Any AstGenerator::visitTypeAliasDeclaration(
antlrcpp::Any AstGenerator::visitVariableDeclaration( antlrcpp::Any AstGenerator::visitVariableDeclaration(
TorqueParser::VariableDeclarationContext* context) { TorqueParser::VariableDeclarationContext* context) {
bool is_const_qualified = context->CONST() != nullptr;
return RegisterNode( return RegisterNode(
new VarDeclarationStatement{Pos(context), new VarDeclarationStatement{Pos(context),
is_const_qualified,
context->IDENTIFIER()->getSymbol()->getText(), context->IDENTIFIER()->getSymbol()->getText(),
GetType(context->type()), GetType(context->type()),
{}}); {}});
......
...@@ -436,9 +436,14 @@ struct TailCallStatement : Statement { ...@@ -436,9 +436,14 @@ struct TailCallStatement : Statement {
struct VarDeclarationStatement : Statement { struct VarDeclarationStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(VarDeclarationStatement) DEFINE_AST_NODE_LEAF_BOILERPLATE(VarDeclarationStatement)
VarDeclarationStatement(SourcePosition p, std::string n, TypeExpression* t, VarDeclarationStatement(SourcePosition p, bool c, std::string n,
base::Optional<Expression*> i) TypeExpression* t, base::Optional<Expression*> i)
: Statement(kKind, p), name(std::move(n)), type(t), initializer(i) {} : Statement(kKind, p),
const_qualified(c),
name(std::move(n)),
type(t),
initializer(i) {}
bool const_qualified;
std::string name; std::string name;
TypeExpression* type; TypeExpression* type;
base::Optional<Expression*> initializer; base::Optional<Expression*> initializer;
......
...@@ -132,19 +132,19 @@ class ModuleConstant : public Value { ...@@ -132,19 +132,19 @@ class ModuleConstant : public Value {
class Variable : public Value { class Variable : public Value {
public: public:
DECLARE_DECLARABLE_BOILERPLATE(Variable, variable); DECLARE_DECLARABLE_BOILERPLATE(Variable, variable);
bool IsConst() const override { return false; } bool IsConst() const override { return const_; }
std::string value() const override { return value_; } std::string value() const override { return value_; }
std::string RValue() const override { std::string RValue() const override {
if (!IsDefined()) { if (!IsDefined()) {
ReportError("Reading uninitialized variable."); ReportError("Reading uninitialized variable.");
} }
std::string result = "(*" + value() + ")"; std::string result = "(*" + value() + ")";
if (!type()->IsConstexpr()) result += ".value()"; if (!IsConst()) result += ".value()";
return result; return result;
} }
void Define() { void Define() {
if (defined_ && type()->IsConstexpr()) { if (defined_ && IsConst()) {
ReportError("Cannot re-define a constexpr variable."); ReportError("Cannot re-define a const-bound variable.");
} }
defined_ = true; defined_ = true;
} }
...@@ -152,13 +152,18 @@ class Variable : public Value { ...@@ -152,13 +152,18 @@ class Variable : public Value {
private: private:
friend class Declarations; friend class Declarations;
Variable(const std::string& name, const std::string& value, const Type* type) Variable(const std::string& name, const std::string& value, const Type* type,
bool is_const)
: Value(Declarable::kVariable, type, name), : Value(Declarable::kVariable, type, name),
value_(value), value_(value),
defined_(false) {} defined_(false),
const_(is_const) {
DCHECK_IMPLIES(type->IsConstexpr(), IsConst());
}
std::string value_; std::string value_;
bool defined_; bool defined_;
bool const_;
}; };
class Label : public Declarable { class Label : public Declarable {
......
...@@ -158,8 +158,9 @@ void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl, ...@@ -158,8 +158,9 @@ void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl,
DeclareSignature(signature); DeclareSignature(signature);
Variable* return_variable = nullptr; Variable* return_variable = nullptr;
if (!signature.return_type->IsVoidOrNever()) { if (!signature.return_type->IsVoidOrNever()) {
return_variable = declarations()->DeclareVariable(kReturnValueVariable, return_variable = declarations()->DeclareVariable(
signature.return_type); kReturnValueVariable, signature.return_type,
signature.return_type->IsConstexpr());
} }
PushControlSplit(); PushControlSplit();
...@@ -254,14 +255,23 @@ void DeclarationVisitor::Visit(ReturnStatement* stmt) { ...@@ -254,14 +255,23 @@ void DeclarationVisitor::Visit(ReturnStatement* stmt) {
void DeclarationVisitor::Visit(VarDeclarationStatement* stmt) { void DeclarationVisitor::Visit(VarDeclarationStatement* stmt) {
std::string variable_name = stmt->name; std::string variable_name = stmt->name;
const Type* type = declarations()->GetType(stmt->type); const Type* type = declarations()->GetType(stmt->type);
if (type->IsConstexpr()) { if (type->IsConstexpr() && !stmt->const_qualified) {
ReportError("cannot declare variable with constexpr type"); ReportError(
"cannot declare variable with constexpr type. Use 'const' instead.");
} }
declarations()->DeclareVariable(variable_name, type); declarations()->DeclareVariable(variable_name, type, stmt->const_qualified);
if (global_context_.verbose()) { if (global_context_.verbose()) {
std::cout << "declared variable " << variable_name << " with type " << *type std::cout << "declared variable " << variable_name << " with type " << *type
<< "\n"; << "\n";
} }
// const qualified variables are required to be initialized properly.
if (stmt->const_qualified && !stmt->initializer) {
std::stringstream stream;
stream << "local constant \"" << variable_name << "\" is not initialized.";
ReportError(stream.str());
}
if (stmt->initializer) { if (stmt->initializer) {
Visit(*stmt->initializer); Visit(*stmt->initializer);
if (global_context_.verbose()) { if (global_context_.verbose()) {
...@@ -399,8 +409,14 @@ void DeclarationVisitor::Visit(TryLabelStatement* stmt) { ...@@ -399,8 +409,14 @@ void DeclarationVisitor::Visit(TryLabelStatement* stmt) {
size_t i = 0; size_t i = 0;
for (auto p : block->parameters.names) { for (auto p : block->parameters.names) {
shared_label->AddVariable(declarations()->DeclareVariable( const Type* type =
p, declarations()->GetType(block->parameters.types[i]))); declarations()->GetType(block->parameters.types[i]);
if (type->IsConstexpr()) {
ReportError("no constexpr type allowed for label arguments");
}
shared_label->AddVariable(
declarations()->DeclareVariable(p, type, false));
++i; ++i;
} }
} }
...@@ -549,9 +565,13 @@ void DeclarationVisitor::DeclareSignature(const Signature& signature) { ...@@ -549,9 +565,13 @@ void DeclarationVisitor::DeclareSignature(const Signature& signature) {
Label* new_label = declarations()->DeclareLabel(label.name); Label* new_label = declarations()->DeclareLabel(label.name);
size_t i = 0; size_t i = 0;
for (auto var_type : label_params) { for (auto var_type : label_params) {
if (var_type->IsConstexpr()) {
ReportError("no constexpr type allowed for label arguments");
}
std::string var_name = label.name + std::to_string(i++); std::string var_name = label.name + std::to_string(i++);
new_label->AddVariable( new_label->AddVariable(
declarations()->DeclareVariable(var_name, var_type)); declarations()->DeclareVariable(var_name, var_type, false));
} }
} }
} }
......
...@@ -288,10 +288,10 @@ RuntimeFunction* Declarations::DeclareRuntimeFunction( ...@@ -288,10 +288,10 @@ RuntimeFunction* Declarations::DeclareRuntimeFunction(
} }
Variable* Declarations::DeclareVariable(const std::string& var, Variable* Declarations::DeclareVariable(const std::string& var,
const Type* type) { const Type* type, bool is_const) {
std::string name(var + std::to_string(GetNextUniqueDeclarationNumber())); std::string name(var + std::to_string(GetNextUniqueDeclarationNumber()));
CheckAlreadyDeclared(var, "variable"); CheckAlreadyDeclared(var, "variable");
Variable* result = new Variable(var, name, type); Variable* result = new Variable(var, name, type, is_const);
Declare(var, std::unique_ptr<Declarable>(result)); Declare(var, std::unique_ptr<Declarable>(result));
return result; return result;
} }
......
...@@ -87,7 +87,8 @@ class Declarations { ...@@ -87,7 +87,8 @@ class Declarations {
RuntimeFunction* DeclareRuntimeFunction(const std::string& name, RuntimeFunction* DeclareRuntimeFunction(const std::string& name,
const Signature& signature); const Signature& signature);
Variable* DeclareVariable(const std::string& var, const Type* type); Variable* DeclareVariable(const std::string& var, const Type* type,
bool is_const);
Parameter* DeclareParameter(const std::string& name, Parameter* DeclareParameter(const std::string& name,
const std::string& mangled_name, const std::string& mangled_name,
......
...@@ -814,10 +814,6 @@ const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) { ...@@ -814,10 +814,6 @@ const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
source_out() << "Return(" << return_result.RValue() << ");" source_out() << "Return(" << return_result.RValue() << ");"
<< std::endl; << std::endl;
} }
} else if (current_callable->IsModuleConstant()) {
Variable* var =
Variable::cast(declarations()->LookupValue(kReturnValueVariable));
GenerateAssignToVariable(var, return_result);
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
...@@ -1231,7 +1227,7 @@ void ImplementationVisitor::GenerateChangedVarsFromControlSplit(AstNode* node) { ...@@ -1231,7 +1227,7 @@ void ImplementationVisitor::GenerateChangedVarsFromControlSplit(AstNode* node) {
source_out() << "{"; source_out() << "{";
bool first = true; bool first = true;
for (auto v : changed_vars) { for (auto v : changed_vars) {
if (v->type()->IsConstexpr()) continue; if (v->IsConst()) continue;
if (first) { if (first) {
first = false; first = false;
} else { } else {
...@@ -1339,7 +1335,7 @@ Variable* ImplementationVisitor::GenerateVariableDeclaration( ...@@ -1339,7 +1335,7 @@ Variable* ImplementationVisitor::GenerateVariableDeclaration(
if (declarations()->TryLookup(name)) { if (declarations()->TryLookup(name)) {
variable = Variable::cast(declarations()->LookupValue(name)); variable = Variable::cast(declarations()->LookupValue(name));
} else { } else {
variable = declarations()->DeclareVariable(name, *type); variable = declarations()->DeclareVariable(name, *type, false);
// Because the variable is being defined during code generation, it must be // Because the variable is being defined during code generation, it must be
// assumed that it changes along all control split paths because it's no // assumed that it changes along all control split paths because it's no
// longer possible to run the control-flow anlaysis in the declaration pass // longer possible to run the control-flow anlaysis in the declaration pass
...@@ -1352,17 +1348,20 @@ Variable* ImplementationVisitor::GenerateVariableDeclaration( ...@@ -1352,17 +1348,20 @@ Variable* ImplementationVisitor::GenerateVariableDeclaration(
GenerateIndent(); GenerateIndent();
if (variable->type()->IsConstexpr()) { if (variable->type()->IsConstexpr()) {
source_out() << variable->type()->GetGeneratedTypeName(); source_out() << variable->type()->GetGeneratedTypeName();
source_out() << " " << variable->value() << "_impl;" << std::endl; source_out() << " " << variable->value() << "_impl;\n";
} else if (variable->IsConst()) {
source_out() << "TNode<" << variable->type()->GetGeneratedTNodeTypeName();
source_out() << "> " << variable->value() << "_impl;\n";
} else { } else {
source_out() << "TVARIABLE("; source_out() << "TVARIABLE(";
source_out() << variable->type()->GetGeneratedTNodeTypeName(); source_out() << variable->type()->GetGeneratedTNodeTypeName();
source_out() << ", " << variable->value() << "_impl);" << std::endl; source_out() << ", " << variable->value() << "_impl);\n";
} }
GenerateIndent(); GenerateIndent();
source_out() << "auto " << variable->value() << " = &" << variable->value() source_out() << "auto " << variable->value() << " = &" << variable->value()
<< "_impl;" << std::endl; << "_impl;\n";
GenerateIndent(); GenerateIndent();
source_out() << "USE(" << variable->value() << ");" << std::endl; source_out() << "USE(" << variable->value() << ");\n";
if (initialization) { if (initialization) {
GenerateAssignToVariable(variable, *initialization); GenerateAssignToVariable(variable, *initialization);
} }
......
...@@ -212,6 +212,18 @@ TEST(TestModuleConstBindings) { ...@@ -212,6 +212,18 @@ TEST(TestModuleConstBindings) {
ft.Call(); ft.Call();
} }
TEST(TestLocalConstBindings) {
Isolate* isolate(CcTest::InitIsolateOnce());
CodeAssemblerTester asm_tester(isolate, 0);
TestBuiltinsFromDSLAssembler m(asm_tester.state());
{
m.TestLocalConstBindings();
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.Call();
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -238,4 +238,9 @@ module test { ...@@ -238,4 +238,9 @@ module test {
check(kIntptrConst == 4); check(kIntptrConst == 4);
check(kSmiConst == 3); check(kSmiConst == 3);
} }
macro TestLocalConstBindings() {
const kSmi: Smi = 3;
check(kSmi == 3);
}
} }
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