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';
ISNT: 'isnt';
IS: 'is';
LET: 'let';
CONST: 'const';
EXTERN: 'extern';
ASSERT_TOKEN: 'assert';
CHECK_TOKEN: 'check';
......@@ -227,7 +228,7 @@ argumentList: '(' argument? (',' argument)* ')';
helperCall: (MIN | MAX | IDENTIFIER) genericSpecializationTypeList? argumentList optionalOtherwise;
labelReference: IDENTIFIER;
variableDeclaration: LET IDENTIFIER ':' type;
variableDeclaration: (LET | CONST) IDENTIFIER ':' type;
variableDeclarationWithInitialization: variableDeclaration (ASSIGNMENT expression)?;
helperCallStatement: (TAIL)? helperCall;
expressionStatement: assignment;
......@@ -277,8 +278,8 @@ externalRuntime : EXTERN RUNTIME IDENTIFIER typeListMaybeVarArgs optionalType ';
builtinDeclaration : JAVASCRIPT? BUILTIN IDENTIFIER optionalGenericTypeList parameterList optionalType (helperBody | ';');
genericSpecialization: IDENTIFIER genericSpecializationTypeList parameterList optionalType optionalLabelList helperBody;
macroDeclaration : ('operator' STRING_LITERAL)? MACRO IDENTIFIER optionalGenericTypeList parameterList optionalType optionalLabelList (helperBody | ';');
externConstDeclaration : 'const' IDENTIFIER ':' type generatesDeclaration ';';
constDeclaration: 'const' IDENTIFIER ':' type ASSIGNMENT expression ';';
externConstDeclaration : CONST IDENTIFIER ':' type generatesDeclaration ';';
constDeclaration: CONST IDENTIFIER ':' type ASSIGNMENT expression ';';
declaration
: typeDeclaration
......
This diff is collapsed.
......@@ -33,29 +33,29 @@ class TorqueLexer : public antlr4::Lexer {
T__17 = 18,
T__18 = 19,
T__19 = 20,
T__20 = 21,
MACRO = 22,
BUILTIN = 23,
RUNTIME = 24,
MODULE = 25,
JAVASCRIPT = 26,
DEFERRED = 27,
IF = 28,
FOR = 29,
WHILE = 30,
RETURN = 31,
CONSTEXPR = 32,
CONTINUE = 33,
BREAK = 34,
GOTO = 35,
OTHERWISE = 36,
TRY = 37,
LABEL = 38,
LABELS = 39,
TAIL = 40,
ISNT = 41,
IS = 42,
LET = 43,
MACRO = 21,
BUILTIN = 22,
RUNTIME = 23,
MODULE = 24,
JAVASCRIPT = 25,
DEFERRED = 26,
IF = 27,
FOR = 28,
WHILE = 29,
RETURN = 30,
CONSTEXPR = 31,
CONTINUE = 32,
BREAK = 33,
GOTO = 34,
OTHERWISE = 35,
TRY = 36,
LABEL = 37,
LABELS = 38,
TAIL = 39,
ISNT = 40,
IS = 41,
LET = 42,
CONST = 43,
EXTERN = 44,
ASSERT_TOKEN = 45,
CHECK_TOKEN = 46,
......
This diff is collapsed.
......@@ -33,29 +33,29 @@ class TorqueParser : public antlr4::Parser {
T__17 = 18,
T__18 = 19,
T__19 = 20,
T__20 = 21,
MACRO = 22,
BUILTIN = 23,
RUNTIME = 24,
MODULE = 25,
JAVASCRIPT = 26,
DEFERRED = 27,
IF = 28,
FOR = 29,
WHILE = 30,
RETURN = 31,
CONSTEXPR = 32,
CONTINUE = 33,
BREAK = 34,
GOTO = 35,
OTHERWISE = 36,
TRY = 37,
LABEL = 38,
LABELS = 39,
TAIL = 40,
ISNT = 41,
IS = 42,
LET = 43,
MACRO = 21,
BUILTIN = 22,
RUNTIME = 23,
MODULE = 24,
JAVASCRIPT = 25,
DEFERRED = 26,
IF = 27,
FOR = 28,
WHILE = 29,
RETURN = 30,
CONSTEXPR = 31,
CONTINUE = 32,
BREAK = 33,
GOTO = 34,
OTHERWISE = 35,
TRY = 36,
LABEL = 37,
LABELS = 38,
TAIL = 39,
ISNT = 40,
IS = 41,
LET = 42,
CONST = 43,
EXTERN = 44,
ASSERT_TOKEN = 45,
CHECK_TOKEN = 46,
......@@ -893,9 +893,10 @@ class TorqueParser : public antlr4::Parser {
VariableDeclarationContext(antlr4::ParserRuleContext* parent,
size_t invokingState);
size_t getRuleIndex() const override;
antlr4::tree::TerminalNode* LET();
antlr4::tree::TerminalNode* IDENTIFIER();
TypeContext* type();
antlr4::tree::TerminalNode* LET();
antlr4::tree::TerminalNode* CONST();
void enterRule(antlr4::tree::ParseTreeListener* listener) override;
void exitRule(antlr4::tree::ParseTreeListener* listener) override;
......@@ -1404,6 +1405,7 @@ class TorqueParser : public antlr4::Parser {
ExternConstDeclarationContext(antlr4::ParserRuleContext* parent,
size_t invokingState);
size_t getRuleIndex() const override;
antlr4::tree::TerminalNode* CONST();
antlr4::tree::TerminalNode* IDENTIFIER();
TypeContext* type();
GeneratesDeclarationContext* generatesDeclaration();
......@@ -1421,6 +1423,7 @@ class TorqueParser : public antlr4::Parser {
ConstDeclarationContext(antlr4::ParserRuleContext* parent,
size_t invokingState);
size_t getRuleIndex() const override;
antlr4::tree::TerminalNode* CONST();
antlr4::tree::TerminalNode* IDENTIFIER();
TypeContext* type();
antlr4::tree::TerminalNode* ASSIGNMENT();
......
......@@ -345,8 +345,10 @@ antlrcpp::Any AstGenerator::visitTypeAliasDeclaration(
antlrcpp::Any AstGenerator::visitVariableDeclaration(
TorqueParser::VariableDeclarationContext* context) {
bool is_const_qualified = context->CONST() != nullptr;
return RegisterNode(
new VarDeclarationStatement{Pos(context),
is_const_qualified,
context->IDENTIFIER()->getSymbol()->getText(),
GetType(context->type()),
{}});
......
......@@ -436,9 +436,14 @@ struct TailCallStatement : Statement {
struct VarDeclarationStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(VarDeclarationStatement)
VarDeclarationStatement(SourcePosition p, std::string n, TypeExpression* t,
base::Optional<Expression*> i)
: Statement(kKind, p), name(std::move(n)), type(t), initializer(i) {}
VarDeclarationStatement(SourcePosition p, bool c, std::string n,
TypeExpression* t, base::Optional<Expression*> i)
: Statement(kKind, p),
const_qualified(c),
name(std::move(n)),
type(t),
initializer(i) {}
bool const_qualified;
std::string name;
TypeExpression* type;
base::Optional<Expression*> initializer;
......
......@@ -132,19 +132,19 @@ class ModuleConstant : public Value {
class Variable : public Value {
public:
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 RValue() const override {
if (!IsDefined()) {
ReportError("Reading uninitialized variable.");
}
std::string result = "(*" + value() + ")";
if (!type()->IsConstexpr()) result += ".value()";
if (!IsConst()) result += ".value()";
return result;
}
void Define() {
if (defined_ && type()->IsConstexpr()) {
ReportError("Cannot re-define a constexpr variable.");
if (defined_ && IsConst()) {
ReportError("Cannot re-define a const-bound variable.");
}
defined_ = true;
}
......@@ -152,13 +152,18 @@ class Variable : public Value {
private:
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_(value),
defined_(false) {}
defined_(false),
const_(is_const) {
DCHECK_IMPLIES(type->IsConstexpr(), IsConst());
}
std::string value_;
bool defined_;
bool const_;
};
class Label : public Declarable {
......
......@@ -158,8 +158,9 @@ void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl,
DeclareSignature(signature);
Variable* return_variable = nullptr;
if (!signature.return_type->IsVoidOrNever()) {
return_variable = declarations()->DeclareVariable(kReturnValueVariable,
signature.return_type);
return_variable = declarations()->DeclareVariable(
kReturnValueVariable, signature.return_type,
signature.return_type->IsConstexpr());
}
PushControlSplit();
......@@ -254,14 +255,23 @@ void DeclarationVisitor::Visit(ReturnStatement* stmt) {
void DeclarationVisitor::Visit(VarDeclarationStatement* stmt) {
std::string variable_name = stmt->name;
const Type* type = declarations()->GetType(stmt->type);
if (type->IsConstexpr()) {
ReportError("cannot declare variable with constexpr type");
if (type->IsConstexpr() && !stmt->const_qualified) {
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()) {
std::cout << "declared variable " << variable_name << " with type " << *type
<< "\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) {
Visit(*stmt->initializer);
if (global_context_.verbose()) {
......@@ -399,8 +409,14 @@ void DeclarationVisitor::Visit(TryLabelStatement* stmt) {
size_t i = 0;
for (auto p : block->parameters.names) {
shared_label->AddVariable(declarations()->DeclareVariable(
p, declarations()->GetType(block->parameters.types[i])));
const Type* type =
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;
}
}
......@@ -549,9 +565,13 @@ void DeclarationVisitor::DeclareSignature(const Signature& signature) {
Label* new_label = declarations()->DeclareLabel(label.name);
size_t i = 0;
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++);
new_label->AddVariable(
declarations()->DeclareVariable(var_name, var_type));
declarations()->DeclareVariable(var_name, var_type, false));
}
}
}
......
......@@ -288,10 +288,10 @@ RuntimeFunction* Declarations::DeclareRuntimeFunction(
}
Variable* Declarations::DeclareVariable(const std::string& var,
const Type* type) {
const Type* type, bool is_const) {
std::string name(var + std::to_string(GetNextUniqueDeclarationNumber()));
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));
return result;
}
......
......@@ -87,7 +87,8 @@ class Declarations {
RuntimeFunction* DeclareRuntimeFunction(const std::string& name,
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,
const std::string& mangled_name,
......
......@@ -814,10 +814,6 @@ const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
source_out() << "Return(" << return_result.RValue() << ");"
<< std::endl;
}
} else if (current_callable->IsModuleConstant()) {
Variable* var =
Variable::cast(declarations()->LookupValue(kReturnValueVariable));
GenerateAssignToVariable(var, return_result);
} else {
UNREACHABLE();
}
......@@ -1231,7 +1227,7 @@ void ImplementationVisitor::GenerateChangedVarsFromControlSplit(AstNode* node) {
source_out() << "{";
bool first = true;
for (auto v : changed_vars) {
if (v->type()->IsConstexpr()) continue;
if (v->IsConst()) continue;
if (first) {
first = false;
} else {
......@@ -1339,7 +1335,7 @@ Variable* ImplementationVisitor::GenerateVariableDeclaration(
if (declarations()->TryLookup(name)) {
variable = Variable::cast(declarations()->LookupValue(name));
} else {
variable = declarations()->DeclareVariable(name, *type);
variable = declarations()->DeclareVariable(name, *type, false);
// 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
// longer possible to run the control-flow anlaysis in the declaration pass
......@@ -1352,17 +1348,20 @@ Variable* ImplementationVisitor::GenerateVariableDeclaration(
GenerateIndent();
if (variable->type()->IsConstexpr()) {
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 {
source_out() << "TVARIABLE(";
source_out() << variable->type()->GetGeneratedTNodeTypeName();
source_out() << ", " << variable->value() << "_impl);" << std::endl;
source_out() << ", " << variable->value() << "_impl);\n";
}
GenerateIndent();
source_out() << "auto " << variable->value() << " = &" << variable->value()
<< "_impl;" << std::endl;
<< "_impl;\n";
GenerateIndent();
source_out() << "USE(" << variable->value() << ");" << std::endl;
source_out() << "USE(" << variable->value() << ");\n";
if (initialization) {
GenerateAssignToVariable(variable, *initialization);
}
......
......@@ -212,6 +212,18 @@ TEST(TestModuleConstBindings) {
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 internal
} // namespace v8
......@@ -238,4 +238,9 @@ module test {
check(kIntptrConst == 4);
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