public override LLVMValueRef Emit(EmittingContext pContext) { pContext.EmitDebugLocation(this); var cond = Condition.Emit(pContext); Utils.LlvmHelper.LoadIfPointer(ref cond, pContext); var endBlock = LLVM.AppendBasicBlock(pContext.CurrentMethod, "endswitch"); LLVMBasicBlockRef elseBlock; pContext.BreakLocations.Push(endBlock); var builder = LLVM.CreateBuilder(); //Default case has to be the last one if (Cases[Cases.Count - 1].IsDefault) { //Emit else into our else block var b = pContext.Builder; pContext.SetBuilder(builder); elseBlock = Cases[Cases.Count - 1].Emit(pContext); pContext.SetBuilder(b); } else { //No else, so this is just an empty block elseBlock = LLVM.AppendBasicBlock(pContext.CurrentMethod, "else"); } LLVM.PositionBuilderAtEnd(builder, elseBlock); var s = LLVM.BuildSwitch(pContext.Builder, cond, elseBlock, (uint)Cases.Count); for (int i = 0; i < Cases.Count; i++) { if (!Cases[i].IsDefault) { //Emit case and jump to end var c = Cases[i].Emit(pContext); LLVM.BuildBr(pContext.Builder, endBlock); foreach (var cs in Cases[i].Conditions) { LLVM.AddCase(s, cs.Emit(pContext), c); } } } LLVM.PositionBuilderAtEnd(pContext.Builder, endBlock); pContext.BreakLocations.Pop(); //Jump from our else block to the end LLVM.BuildBr(builder, endBlock); LLVM.DisposeBuilder(builder); return(default);
public void AddCase(ConstantInt onVal, BasicBlock dest) => LLVM.AddCase(this.Unwrap(), onVal.Unwrap(), dest.Unwrap <LLVMBasicBlockRef>());
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(); }