-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSwitchStatement.cs
More file actions
113 lines (99 loc) · 4.86 KB
/
SwitchStatement.cs
File metadata and controls
113 lines (99 loc) · 4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
namespace MiniSharpCompiler
{
using System;
using System.Collections.Generic;
using LLVMSharp;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
public partial class LLVMIRGenerationVisitor
{
public override void VisitSwitchStatement(SwitchStatementSyntax node)
{
var @default = LLVM.AppendBasicBlock(this.function, "sw.default");
var epilog = LLVM.AppendBasicBlock(this.function, "sw.epilog");
bool defaultEpilogWritten = false;
this.controlFlowStack.Push(new ControlFlowTarget(epilog, epilog));
var governingType = this.semanticModel.GetTypeInfo(node.Expression);
var governingLLVMType = governingType.LLVMTypeRef();
var @switch = LLVM.BuildSwitch(this.builder, this.Pop(node.Expression), @default, (uint)node.Sections.Count);
this.currentSwitchStatement = new Dictionary<object, LLVMBasicBlockRef>();
foreach (var section in node.Sections)
{
var sectionLabels = section.Labels;
LLVMBasicBlockRef bb = @default;
bool isDefault = false;
foreach (SwitchLabelSyntax label in sectionLabels)
{
if (label.Keyword.IsKind(SyntaxKind.DefaultKeyword))
{
defaultEpilogWritten = true;
isDefault = true;
}
}
if (!isDefault)
{
bb = LLVM.AppendBasicBlock(this.function, "sw.bb");
}
foreach (SwitchLabelSyntax label in sectionLabels)
{
switch (label.Keyword.Kind())
{
case SyntaxKind.DefaultKeyword:
this.currentSwitchStatement.Add(defaultHash, bb);
break;
case SyntaxKind.CaseKeyword:
ulong constantValue;
var caseLabel = (CaseSwitchLabelSyntax) label;
var typeInfo = this.semanticModel.GetTypeInfo(caseLabel.Value);
object constantValueObject = this.semanticModel.GetConstantValue(caseLabel.Value).Value;
switch (typeInfo.Type.SpecialType)
{
case SpecialType.System_Boolean:
constantValue = (bool)constantValueObject ? 1U : 0;
break;
case SpecialType.System_Byte:
case SpecialType.System_Char:
case SpecialType.System_UInt16:
case SpecialType.System_UInt32:
case SpecialType.System_UInt64:
constantValue = (ulong)constantValueObject;
break;
case SpecialType.System_SByte:
case SpecialType.System_Int16:
case SpecialType.System_Int32:
constantValue = (ulong)((int)(constantValueObject));
break;
case SpecialType.System_Int64:
constantValue = (ulong)((long) constantValueObject);
break;
case SpecialType.System_String:
throw new NotImplementedException("Switch on string type is not implemented");
default:
throw new Exception("Unreachable");
}
LLVM.AddCase(@switch, LLVM.ConstInt(governingLLVMType, constantValue, governingType.IsSignExtended()), bb);
this.currentSwitchStatement.Add(constantValueObject, bb);
break;
default:
throw new Exception("Unreachable");
}
}
LLVM.PositionBuilderAtEnd(this.builder, bb);
foreach (var statement in section.Statements)
{
this.Visit(statement);
}
LLVM.BuildBr(this.builder, epilog);
}
this.currentSwitchStatement = null;
if (!defaultEpilogWritten)
{
LLVM.PositionBuilderAtEnd(this.builder, @default);
LLVM.BuildBr(this.builder, epilog);
}
LLVM.PositionBuilderAtEnd(this.builder, epilog);
this.controlFlowStack.Pop();
}
}
}