void AppendOp(SSA.Value v, bool isConst = false) { switch (v.op) { case Op.FunctionArgument: case Op.ConstAggregateZero: case Op.ConstInt: case Op.ConstReal: case Op.ConstArray: case Op.ConstStruct: case Op.ConstPtr: case Op.ConstVoid: case Op.Label: throw new InvalidCodePath(); case Op.Function: { Debug.Assert(!isConst); var f = (Function)v; bool declare; if (f.blocks == null || f.blocks.Count == 0) { AP("declare "); declare = true; } else { AP("define "); if (f.exportDLL) { AP("dllexport "); } if (!f.exportDLL && f.internalLinkage) { AP("internal "); } declare = false; } var pt = (PointerType)f.type; var ft = (FunctionType)pt.elementType; AppendType(ft.returnType); AP($" {f.name}("); for (int i = 0; i < f.args.Count; ++i) { var arg = (FunctionArgument)f.args[i]; Debug.Assert(arg.op == Op.FunctionArgument); AppendType(arg.type); if (arg.noalias) { AP(" noalias"); } if (arg.nocapture) { AP(" nocapture"); } if (arg.@readonly) { AP(" readonly"); } if (!declare) { AP($" {arg.name}"); } if (i != f.args.Count - 1) { AP($", "); } } var attribIdx = AddAttrib(f.attribs); if (!declare) { AP($") #{attribIdx}"); AppendFunctionDebugInfo(v); AL(" {"); foreach (var b in f.blocks) { debugCurrentEmitBlock = b; AL($"{b.name.Substring(1)}:"); isIndented = true; if (b.name == "%vars") { AppendFunctionArgumentsDebugInfo(v); } foreach (var op in b.args) { AppendOp(op); } isIndented = false; } AL("}"); } else { AL($") #{attribIdx}"); } AL(); } break; case Op.GlobalStringPtr: { if (!isConst) { var gsp = (GlobalStringPtr)v; var es = EscapeString(gsp.data); AL($"{gsp.name} = private unnamed_addr constant [{gsp.data.Length + 1} x i8] c\"{es}\\00\""); } else { AP(v.name); } } break; case Op.GlobalVariable: { if (!isConst) { var gv = (GlobalVariable)v; AppendAssignSSA(gv); AP($"internal global {(gv.isConstantVariable ? "constant " : "")}"); var pt = (PointerType)gv.type; AppendType(pt.elementType); AP(" "); AppendConstValue(gv.initializer); AppendGlobalVariableDebugInfo(gv); if (v.alignment > 0) { AP($", align {v.alignment}"); } AL(); } else { AP(v.name); } } break; case Op.Br: { if (v.args.Count == 1) { Debug.Assert(!isConst); Indent(); AP("br "); AppendArgument(v.args[0]); AppendDebugInfo(v); AL(); } else { Indent(); AP("br "); AppendArgument(v.args[0]); AP(", "); AppendArgument(v.args[1]); AP(", "); AppendArgument(v.args[2]); AppendDebugInfo(v); AL(); } } break; case Op.Phi: { AppendAssignSSA(v); AP("phi "); AppendType(v.type); AP(" "); var phi = (Phi)v; for (int i = 0; i < phi.incoming.Count; ++i) { AP("[ "); var inc = phi.incoming[i]; AppendArgument(inc.v, false); AP(", "); AppendArgument(inc.b, false); AP(" ]"); if (i != phi.incoming.Count - 1) { AP(", "); } } AppendDebugInfo(v); AL(); } break; case Op.Call: { Debug.Assert(!isConst); if (v.type.kind != TypeKind.Void) { AppendAssignSSA(v); } else { Indent(); } var fun = v.args[0]; var pt = (PointerType)fun.type; var ft = (FunctionType)pt.elementType; if (fun is Function f && f.attribs.HasFlag(FunctionAttribs.lvvm)) { AP($"{f.name.Substring(1)} "); for (int i = 1; i < v.args.Count; ++i) { AppendArgument(v.args[i]); if (i != v.args.Count - 1) { AP(", "); } } }
void AppendConstValue(SSA.Value v) { switch (v) { case ConstInt i: var it = i.type as IntegerType; if (it.bitWidth == 1) { if (i.flags.HasFlag(SSAFlags.undef)) { AP("undef"); } else if (i.data == 0) { AP("false"); } else { AP("true"); } } else { if (i.flags.HasFlag(SSAFlags.undef)) { AP("undef"); } else { AP(i.data.ToString()); } } break; case ConstReal r: string fs = null; var rt = (FloatType)r.type; if (r.flags.HasFlag(SSAFlags.undef)) { AP("undef"); } else if (rt.width == FloatType.FloatWidths.fp64) { var bytes = BitConverter.GetBytes(r.data); var number = BitConverter.ToUInt64(bytes, 0); fs = $"0x{number.ToString("X16", nfi)}"; } else if (rt.width == FloatType.FloatWidths.fp32) { var f32 = (float)r.data; var bytes = BitConverter.GetBytes((double)f32); var number = BitConverter.ToUInt64(bytes, 0);; fs = $"0x{number.ToString("X16", nfi)}"; } else if (rt.width == FloatType.FloatWidths.fp16) { throw new NotImplementedException(); } AP(fs); break; case ConstPtr p: if (p.flags.HasFlag(SSAFlags.undef)) { AP("undef"); } else if (p.data == 0) { AP("null"); } else { AP(p.data.ToString()); } break; case ConstArray a: { AP("[ "); for (int i = 0; i < a.data.Count; ++i) { var d = a.data[i]; AppendType(d.type); AP(" "); AppendConstValue(d); if (i != a.data.Count - 1) { AP(", "); } } AP(" ]"); } break; case ConstStruct st: { if (!st.packed) { AP("{ "); } else { AP("<{ "); } for (int i = 0; i < st.elements.Count; ++i) { var el = st.elements[i]; AppendType(el.type); AP(" "); AppendConstValue(el); if (i != st.elements.Count - 1) { AP(", "); } } if (!st.packed) { AP(" }"); } else { AP(" }>"); } } break; case ConstVec vec: { AP("<"); var vt = (VectorType)vec.type; for (int i = 0; i < vt.elementCount; ++i) { var el = vec.elements[i]; AppendType(el.type); AP(" "); AppendConstValue(el); if (i != vt.elementCount - 1) { AP(", "); } } AP(">"); } break; case Value caz when caz.op == Op.ConstAggregateZero: AP("zeroinitializer"); break; default: AppendOp(v, true); break; } }