true and false support, and lowering for bool type. (#2896)

This commit is contained in:
Richard Smith
2023-06-13 16:43:03 -07:00
committed by GitHub
parent 8e940d9724
commit aa40e2b8a9
15 changed files with 198 additions and 5 deletions
+2
View File
@@ -131,6 +131,7 @@ CARBON_KEYWORD_TOKEN(Default, "default")
CARBON_KEYWORD_TOKEN(Else, "else")
CARBON_KEYWORD_TOKEN(Extends, "extends")
CARBON_KEYWORD_TOKEN(External, "external")
CARBON_KEYWORD_TOKEN(False, "false")
CARBON_KEYWORD_TOKEN(Final, "final")
CARBON_KEYWORD_TOKEN(Fn, "fn")
CARBON_KEYWORD_TOKEN(For, "for")
@@ -162,6 +163,7 @@ CARBON_KEYWORD_TOKEN(SelfValueIdentifier, "self")
CARBON_KEYWORD_TOKEN(StringTypeLiteral, "String")
CARBON_KEYWORD_TOKEN(Template, "template")
CARBON_KEYWORD_TOKEN(Then, "then")
CARBON_KEYWORD_TOKEN(True, "true")
// Underscore is tokenized as a keyword because it's part of identifiers.
CARBON_KEYWORD_TOKEN(Underscore, "_")
CARBON_KEYWORD_TOKEN(Var, "var")
+4
View File
@@ -141,6 +141,10 @@ auto LoweringContext::BuildType(SemanticsNodeId node_id) -> llvm::Type* {
case SemanticsBuiltinKind::IntegerType.AsInt():
// TODO: Handle different sizes.
return builder_.getInt32Ty();
case SemanticsBuiltinKind::BoolType.AsInt():
// TODO: We may want to have different representations for `bool` storage
// (`i8`) versus for `bool` values (`i1`).
return builder_.getInt1Ty();
}
auto node = semantics_ir_->GetNode(node_id);
+8
View File
@@ -43,6 +43,14 @@ auto LoweringHandleBlockArg(LoweringContext& /*context*/,
CARBON_FATAL() << "TODO: Add support: " << node;
}
auto LoweringHandleBoolLiteral(LoweringContext& context,
SemanticsNodeId node_id, SemanticsNode node)
-> void {
llvm::Value* v = llvm::ConstantInt::get(context.builder().getInt1Ty(),
node.GetAsBoolLiteral().index);
context.SetLocal(node_id, v);
}
auto LoweringHandleBranch(LoweringContext& /*context*/,
SemanticsNodeId /*node_id*/, SemanticsNode node)
-> void {
+25
View File
@@ -0,0 +1,25 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// CHECK:STDOUT: ; ModuleID = 'false_true.carbon'
// CHECK:STDOUT: source_filename = "false_true.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: define i1 @F() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: ret i1 false
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define i1 @T() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: ret i1 true
// CHECK:STDOUT: }
fn F() -> bool {
return false;
}
fn T() -> bool {
return true;
}
@@ -61,6 +61,8 @@ auto ParserHandleExpressionInPostfix(ParserContext& context) -> void {
context.PushState(state);
break;
}
case TokenKind::False:
case TokenKind::True:
case TokenKind::IntegerLiteral:
case TokenKind::RealLiteral:
case TokenKind::StringLiteral:
@@ -14,7 +14,7 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'Literal', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
// CHECK:STDOUT: {kind: 'Literal', text: '1'},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', subtree_size: 2},
@@ -14,7 +14,7 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'Literal', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
// CHECK:STDOUT: {kind: 'Literal', text: '1'},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', subtree_size: 2},
@@ -14,7 +14,7 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'Literal', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', has_error: yes, subtree_size: 2},
@@ -14,7 +14,7 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'Literal', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
@@ -10,7 +10,7 @@
// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'IfConditionStart', text: 'if', has_error: yes},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'Literal', text: 'true'},
// CHECK:STDOUT: {kind: 'IfCondition', text: 'if', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'CodeBlockStart', text: 'then', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: 'then', has_error: yes},
+11
View File
@@ -224,6 +224,17 @@ auto SemanticsHandleLiteral(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
auto token = context.parse_tree().node_token(parse_node);
switch (auto token_kind = context.tokens().GetKind(token)) {
case TokenKind::False:
case TokenKind::True: {
context.AddNodeAndPush(
parse_node,
SemanticsNode::BoolLiteral::Make(
parse_node,
context.CanonicalizeType(SemanticsNodeId::BuiltinBoolType),
token_kind == TokenKind::True ? SemanticsBoolValue(1)
: SemanticsBoolValue(0)));
break;
}
case TokenKind::IntegerLiteral: {
auto id = context.semantics_ir().AddIntegerLiteral(
context.tokens().GetIntegerLiteral(token));
+1
View File
@@ -199,6 +199,7 @@ auto SemanticsIR::StringifyType(SemanticsTypeId type_id) -> std::string {
case SemanticsNodeKind::BinaryOperatorAdd:
case SemanticsNodeKind::BindName:
case SemanticsNodeKind::BlockArg:
case SemanticsNodeKind::BoolLiteral:
case SemanticsNodeKind::Branch:
case SemanticsNodeKind::BranchIf:
case SemanticsNodeKind::BranchWithArg:
+20
View File
@@ -68,6 +68,23 @@ struct SemanticsCrossReferenceIRId : public IndexBase {
}
};
// A boolean value.
struct SemanticsBoolValue : public IndexBase {
using IndexBase::IndexBase;
auto Print(llvm::raw_ostream& out) const -> void {
switch (index) {
case 0:
out << "false";
break;
case 1:
out << "true";
break;
default:
CARBON_FATAL() << "Invalid bool value " << index;
}
}
};
// The ID of an integer literal.
struct SemanticsIntegerLiteralId : public IndexBase {
using IndexBase::IndexBase;
@@ -264,6 +281,9 @@ class SemanticsNode {
using BlockArg = Factory<SemanticsNodeKind::BlockArg>;
using BoolLiteral =
Factory<SemanticsNodeKind::BoolLiteral, SemanticsBoolValue /*value*/>;
using Branch = FactoryNoType<SemanticsNodeKind::Branch,
SemanticsNodeBlockId /*target_id*/>;
@@ -24,6 +24,7 @@ CARBON_SEMANTICS_NODE_KIND(Assign)
CARBON_SEMANTICS_NODE_KIND(BinaryOperatorAdd)
CARBON_SEMANTICS_NODE_KIND(BindName)
CARBON_SEMANTICS_NODE_KIND(BlockArg)
CARBON_SEMANTICS_NODE_KIND(BoolLiteral)
CARBON_SEMANTICS_NODE_KIND(Branch)
CARBON_SEMANTICS_NODE_KIND(BranchIf)
CARBON_SEMANTICS_NODE_KIND(BranchWithArg)
@@ -0,0 +1,119 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, return_type: type0, body: block2},
// CHECK:STDOUT: {name: str1, param_refs: block0, return_type: type0, body: block3},
// CHECK:STDOUT: {name: str2, param_refs: block0, return_type: type0, body: block4},
// CHECK:STDOUT: {name: str3, param_refs: block0, return_type: type0, body: block8},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
// CHECK:STDOUT: 2,
// CHECK:STDOUT: ]
// CHECK:STDOUT: real_literals: [
// CHECK:STDOUT: ]
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: A,
// CHECK:STDOUT: B,
// CHECK:STDOUT: F,
// CHECK:STDOUT: G,
// CHECK:STDOUT: ]
// CHECK:STDOUT: types: [
// CHECK:STDOUT: nodeIntegerType,
// CHECK:STDOUT: nodeBoolType,
// CHECK:STDOUT: ]
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+1, type: type0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+4, type: type0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function2},
// CHECK:STDOUT: {kind: BoolLiteral, arg0: true, type: type1},
// CHECK:STDOUT: {kind: BranchIf, arg0: block6, arg1: node+7},
// CHECK:STDOUT: {kind: Branch, arg0: block5},
// CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function0, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function1, type: type0},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block7, arg1: node+10},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block7, arg1: node+11},
// CHECK:STDOUT: {kind: BlockArg, type: type0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+14, type: type0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function3},
// CHECK:STDOUT: {kind: BoolLiteral, arg0: false, type: type1},
// CHECK:STDOUT: {kind: BranchIf, arg0: block10, arg1: node+17},
// CHECK:STDOUT: {kind: Branch, arg0: block9},
// CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function0, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function1, type: type0},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block11, arg1: node+20},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block11, arg1: node+21},
// CHECK:STDOUT: {kind: BlockArg, type: type0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+24, type: type0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+16,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: node+13,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: node+12,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+14,
// CHECK:STDOUT: node+15,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+17,
// CHECK:STDOUT: node+18,
// CHECK:STDOUT: node+19,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+21,
// CHECK:STDOUT: node+23,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+20,
// CHECK:STDOUT: node+22,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+24,
// CHECK:STDOUT: node+25,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn A() -> i32 { return 1; }
fn B() -> i32 { return 2; }
fn F() -> i32 {
return if true then A() else B();
}
fn G() -> i32 {
return if false then A() else B();
}