PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/println.go

https://github.com/gregghz/llgo
Go | 176 lines | 151 code | 17 blank | 8 comment | 16 complexity | 75eb456338138dd353ba54f8b9caf895 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright 2011 The llgo Authors.
  2. // Use of this source code is governed by an MIT-style
  3. // license that can be found in the LICENSE file.
  4. package llgo
  5. import (
  6. "code.google.com/p/go.tools/go/types"
  7. "fmt"
  8. "github.com/greggoryhz/gollvm/llvm"
  9. "go/ast"
  10. )
  11. func getprintf(module llvm.Module) llvm.Value {
  12. printf := module.NamedFunction("printf")
  13. if printf.IsNil() {
  14. CharPtr := llvm.PointerType(llvm.Int8Type(), 0)
  15. fn_type := llvm.FunctionType(
  16. llvm.Int32Type(), []llvm.Type{CharPtr}, true)
  17. printf = llvm.AddFunction(module, "printf", fn_type)
  18. printf.SetFunctionCallConv(llvm.CCallConv)
  19. }
  20. return printf
  21. }
  22. func (c *compiler) getBoolString(v llvm.Value) llvm.Value {
  23. startBlock := c.builder.GetInsertBlock()
  24. resultBlock := llvm.InsertBasicBlock(startBlock, "")
  25. resultBlock.MoveAfter(startBlock)
  26. falseBlock := llvm.InsertBasicBlock(resultBlock, "")
  27. CharPtr := llvm.PointerType(llvm.Int8Type(), 0)
  28. falseString := c.builder.CreateGlobalStringPtr("false", "")
  29. falseString = c.builder.CreateBitCast(falseString, CharPtr, "")
  30. trueString := c.builder.CreateGlobalStringPtr("true", "")
  31. trueString = c.builder.CreateBitCast(trueString, CharPtr, "")
  32. c.builder.CreateCondBr(v, resultBlock, falseBlock)
  33. c.builder.SetInsertPointAtEnd(falseBlock)
  34. c.builder.CreateBr(resultBlock)
  35. c.builder.SetInsertPointAtEnd(resultBlock)
  36. result := c.builder.CreatePHI(CharPtr, "")
  37. result.AddIncoming([]llvm.Value{trueString, falseString},
  38. []llvm.BasicBlock{startBlock, falseBlock})
  39. return result
  40. }
  41. func (c *compiler) printValues(println_ bool, values ...Value) Value {
  42. var args []llvm.Value = nil
  43. if len(values) > 0 {
  44. format := ""
  45. args = make([]llvm.Value, 0, len(values)+1)
  46. for i, value := range values {
  47. llvm_value := value.LLVMValue()
  48. typ := value.Type().Underlying()
  49. if name, isname := typ.(*types.Named); isname {
  50. typ = name.Underlying()
  51. }
  52. if println_ && i > 0 {
  53. format += " "
  54. }
  55. switch typ := typ.(type) {
  56. case *types.Basic:
  57. switch typ.Kind() {
  58. case types.Uint8:
  59. format += "%hhu"
  60. case types.Uint16:
  61. format += "%hu"
  62. case types.Uint32:
  63. format += "%u"
  64. case types.Uintptr, types.Uint:
  65. format += "%lu"
  66. case types.Uint64:
  67. format += "%llu" // FIXME windows
  68. case types.Int:
  69. format += "%ld"
  70. case types.Int8:
  71. format += "%hhd"
  72. case types.Int16:
  73. format += "%hd"
  74. case types.Int32:
  75. format += "%d"
  76. case types.Int64:
  77. format += "%lld" // FIXME windows
  78. case types.Float32:
  79. llvm_value = c.builder.CreateFPExt(llvm_value, llvm.DoubleType(), "")
  80. fallthrough
  81. case types.Float64:
  82. printfloat := c.NamedFunction("runtime.printfloat", "func f(float64) string")
  83. args := []llvm.Value{llvm_value}
  84. llvm_value = c.builder.CreateCall(printfloat, args, "")
  85. fallthrough
  86. case types.String, types.UntypedString:
  87. ptrval := c.builder.CreateExtractValue(llvm_value, 0, "")
  88. lenval := c.builder.CreateExtractValue(llvm_value, 1, "")
  89. llvm_value = ptrval
  90. args = append(args, lenval)
  91. format += "%.*s"
  92. case types.Bool:
  93. format += "%s"
  94. llvm_value = c.getBoolString(llvm_value)
  95. case types.UnsafePointer:
  96. format += "%p"
  97. default:
  98. panic(fmt.Sprint("Unhandled Basic Kind: ", typ.Kind))
  99. }
  100. case *types.Interface:
  101. format += "(0x%lx,0x%lx)"
  102. ival := c.builder.CreateExtractValue(llvm_value, 0, "")
  103. itype := c.builder.CreateExtractValue(llvm_value, 1, "")
  104. args = append(args, ival)
  105. llvm_value = itype
  106. case *types.Slice, *types.Array:
  107. // If we see a constant array, we either:
  108. // Create an internal constant if it's a constant array, or
  109. // Create space on the stack and store it there.
  110. init_ := value.(*LLVMValue)
  111. if init_.pointer != nil {
  112. llvm_value = init_.pointer.LLVMValue()
  113. } else {
  114. init_value := init_.LLVMValue()
  115. llvm_value = c.builder.CreateAlloca(init_value.Type(), "")
  116. c.builder.CreateStore(init_value, llvm_value)
  117. }
  118. // FIXME don't assume string...
  119. format += "%s"
  120. case *types.Pointer:
  121. format += "0x%lx"
  122. default:
  123. panic(fmt.Sprintf("Unhandled type kind: %s (%T)", typ, typ))
  124. }
  125. args = append(args, llvm_value)
  126. }
  127. if println_ {
  128. format += "\n"
  129. }
  130. formatval := c.builder.CreateGlobalStringPtr(format, "")
  131. args = append([]llvm.Value{formatval}, args...)
  132. } else {
  133. var format string
  134. if println_ {
  135. format = "\n"
  136. }
  137. args = []llvm.Value{c.builder.CreateGlobalStringPtr(format, "")}
  138. }
  139. printf := getprintf(c.module.Module)
  140. result := c.NewValue(c.builder.CreateCall(printf, args, ""), types.Typ[types.Int32])
  141. fflush := c.NamedFunction("fflush", "func f(*int32) int32")
  142. c.builder.CreateCall(fflush, []llvm.Value{llvm.ConstNull(llvm.PointerType(llvm.Int32Type(), 0))}, "")
  143. return result
  144. }
  145. func (c *compiler) visitPrint(expr *ast.CallExpr) Value {
  146. var values []Value
  147. for _, arg := range expr.Args {
  148. values = append(values, c.VisitExpr(arg))
  149. }
  150. return c.printValues(false, values...)
  151. }
  152. func (c *compiler) visitPrintln(expr *ast.CallExpr) Value {
  153. var values []Value
  154. for _, arg := range expr.Args {
  155. values = append(values, c.VisitExpr(arg))
  156. }
  157. return c.printValues(true, values...)
  158. }
  159. // vim: set ft=go :