Example #1
0
func (in *interp) makeCompilerOptions() error {
	prefix, err := getInstPrefix()
	if err != nil {
		return err
	}

	importPaths := []string{filepath.Join(prefix, "lib", "go", "llgo-"+llvmVersion())}
	in.copts = irgen.CompilerOptions{
		TargetTriple:  llvm.DefaultTargetTriple(),
		ImportPaths:   importPaths,
		GenerateDebug: true,
		Packages:      in.pkgmap,
	}
	err = in.copts.MakeImporter()
	if err != nil {
		return err
	}

	origImporter := in.copts.Importer
	in.copts.Importer = func(pkgmap map[string]*types.Package, pkgpath string) (*types.Package, error) {
		if pkg, ok := pkgmap[pkgpath]; ok && pkg.Complete() {
			return pkg, nil
		}
		return origImporter(pkgmap, pkgpath)
	}
	return nil
}
Example #2
0
File: codegen.go Project: vnev/ark
func (v *Codegen) Generate(input []*parser.Module) {
	v.builders = make(map[*parser.Function]llvm.Builder)
	v.inBlocks = make(map[*parser.Function][]*parser.Block)
	v.globalBuilder = llvm.NewBuilder()
	defer v.globalBuilder.Dispose()

	v.curLoopExits = make(map[*parser.Function][]llvm.BasicBlock)
	v.curLoopNexts = make(map[*parser.Function][]llvm.BasicBlock)

	v.input = make([]*WrappedModule, len(input))
	for idx, mod := range input {
		v.input[idx] = &WrappedModule{Module: mod}
	}

	v.variableLookup = make(map[*parser.Variable]llvm.Value)
	v.namedTypeLookup = make(map[string]llvm.Type)

	// initialize llvm target
	llvm.InitializeNativeTarget()
	llvm.InitializeNativeAsmPrinter()

	// setup target stuff
	var err error
	v.target, err = llvm.GetTargetFromTriple(llvm.DefaultTargetTriple())
	if err != nil {
		panic(err)
	}
	v.targetMachine = v.target.CreateTargetMachine(llvm.DefaultTargetTriple(), "", "", llvm.CodeGenLevelNone, llvm.RelocDefault, llvm.CodeModelDefault)
	v.targetData = v.targetMachine.TargetData()

	passManager := llvm.NewPassManager()
	passBuilder := llvm.NewPassManagerBuilder()
	if v.OptLevel > 0 {
		passBuilder.SetOptLevel(v.OptLevel)
		passBuilder.Populate(passManager)
	}

	v.blockDeferData = make(map[*parser.Block][]*deferData)

	for _, infile := range v.input {
		log.Timed("codegenning", infile.Name.String(), func() {
			infile.LlvmModule = llvm.NewModule(infile.Name.String())
			v.curFile = infile

			for _, submod := range infile.Parts {
				v.declareDecls(submod.Nodes)

				for _, node := range submod.Nodes {
					v.genNode(node)
				}
			}

			if err := llvm.VerifyModule(infile.LlvmModule, llvm.ReturnStatusAction); err != nil {
				infile.LlvmModule.Dump()
				v.err("%s", err.Error())
			}

			passManager.Run(infile.LlvmModule)

			if log.AtLevel(log.LevelDebug) {
				infile.LlvmModule.Dump()
			}
		})
	}

	passManager.Dispose()

	log.Timed("creating binary", "", func() {
		v.createBinary()
	})

}
Example #3
0
func (v *Codegen) Generate(input []*parser.Module, modules map[string]*parser.Module) {
	v.input = input
	v.builder = llvm.NewBuilder()
	v.variableLookup = make(map[*parser.Variable]llvm.Value)
	v.structLookup_UseHelperFunction = make(map[*parser.StructType]llvm.Type)
	v.enumLookup_UseHelperFunction = make(map[*parser.EnumType]llvm.Type)

	// initialize llvm target
	llvm.InitializeNativeTarget()

	// setup target stuff
	var err error
	v.target, err = llvm.GetTargetFromTriple(llvm.DefaultTargetTriple())
	if err != nil {
		panic(err)
	}
	v.targetMachine = v.target.CreateTargetMachine(llvm.DefaultTargetTriple(), "", "", llvm.CodeGenLevelNone, llvm.RelocDefault, llvm.CodeModelDefault)
	v.targetData = v.targetMachine.TargetData()

	passManager := llvm.NewPassManager()
	passBuilder := llvm.NewPassManagerBuilder()
	if v.OptLevel > 0 {
		passBuilder.SetOptLevel(v.OptLevel)
		passBuilder.Populate(passManager)
	}

	v.modules = make(map[string]*parser.Module)
	v.blockDeferData = make(map[*parser.Block][]*deferData)

	for _, infile := range input {
		log.Verboseln("codegen", util.TEXT_BOLD+util.TEXT_GREEN+"Started codegenning "+util.TEXT_RESET+infile.Name)
		t := time.Now()

		infile.Module = llvm.NewModule(infile.Name)
		v.curFile = infile

		v.modules[v.curFile.Name] = v.curFile

		v.declareDecls(infile.Nodes)

		for _, node := range infile.Nodes {
			v.genNode(node)
		}

		if err := llvm.VerifyModule(infile.Module, llvm.ReturnStatusAction); err != nil {
			infile.Module.Dump()
			v.err("%s", err.Error())
		}

		passManager.Run(infile.Module)

		if log.AtLevel(log.LevelVerbose) {
			infile.Module.Dump()
		}

		dur := time.Since(t)
		log.Verbose("codegen", util.TEXT_BOLD+util.TEXT_GREEN+"Finished codegenning "+util.TEXT_RESET+infile.Name+" (%.2fms)\n",
			float32(dur.Nanoseconds())/1000000)
	}

	passManager.Dispose()

	log.Timed("create binary", func() {
		v.createBinary()
	})

}
Example #4
0
func parseArguments(args []string) (opts driverOptions, err error) {
	var goInputs, otherInputs []string
	hasOtherNonFlagInputs := false
	noPrefix := false
	actionKind := actionLink
	opts.triple = llvm.DefaultTargetTriple()

	for len(args) > 0 {
		consumedArgs := 1

		switch {
		case !strings.HasPrefix(args[0], "-"):
			if strings.HasSuffix(args[0], ".go") {
				goInputs = append(goInputs, args[0])
			} else {
				hasOtherNonFlagInputs = true
				otherInputs = append(otherInputs, args[0])
			}

		case strings.HasPrefix(args[0], "-Wl,"), strings.HasPrefix(args[0], "-l"), strings.HasPrefix(args[0], "--sysroot="):
			// TODO(pcc): Handle these correctly.
			otherInputs = append(otherInputs, args[0])

		case args[0] == "-B":
			if len(args) == 1 {
				return opts, errors.New("missing argument after '-B'")
			}
			opts.bprefix = args[1]
			consumedArgs = 2

		case args[0] == "-D":
			if len(args) == 1 {
				return opts, errors.New("missing argument after '-D'")
			}
			otherInputs = append(otherInputs, args[0], args[1])
			consumedArgs = 2

		case strings.HasPrefix(args[0], "-D"):
			otherInputs = append(otherInputs, args[0])

		case args[0] == "-I":
			if len(args) == 1 {
				return opts, errors.New("missing argument after '-I'")
			}
			opts.importPaths = append(opts.importPaths, args[1])
			consumedArgs = 2

		case strings.HasPrefix(args[0], "-I"):
			opts.importPaths = append(opts.importPaths, args[0][2:])

		case args[0] == "-isystem":
			if len(args) == 1 {
				return opts, errors.New("missing argument after '-isystem'")
			}
			otherInputs = append(otherInputs, args[0], args[1])
			consumedArgs = 2

		case args[0] == "-L":
			if len(args) == 1 {
				return opts, errors.New("missing argument after '-L'")
			}
			opts.libPaths = append(opts.libPaths, args[1])
			consumedArgs = 2

		case strings.HasPrefix(args[0], "-L"):
			opts.libPaths = append(opts.libPaths, args[0][2:])

		case args[0] == "-O0":
			opts.optLevel = 0

		case args[0] == "-O1", args[0] == "-O":
			opts.optLevel = 1

		case args[0] == "-O2":
			opts.optLevel = 2

		case args[0] == "-Os":
			opts.optLevel = 2
			opts.sizeLevel = 1

		case args[0] == "-O3":
			opts.optLevel = 3

		case args[0] == "-S":
			actionKind = actionAssemble

		case args[0] == "-c":
			actionKind = actionCompile

		case strings.HasPrefix(args[0], "-fcompilerrt-prefix="):
			opts.sanitizer.crtPrefix = args[0][20:]

		case strings.HasPrefix(args[0], "-fdebug-prefix-map="):
			split := strings.SplitN(args[0][19:], "=", 2)
			if len(split) < 2 {
				return opts, fmt.Errorf("argument '%s' must be of form '-fdebug-prefix-map=SOURCE=REPLACEMENT'", args[0])
			}
			opts.debugPrefixMaps = append(opts.debugPrefixMaps, debug.PrefixMap{split[0], split[1]})

		case args[0] == "-fdump-ssa":
			opts.dumpSSA = true

		case args[0] == "-fdump-trace":
			opts.dumpTrace = true

		case strings.HasPrefix(args[0], "-fgccgo-path="):
			opts.gccgoPath = args[0][13:]

		case strings.HasPrefix(args[0], "-fgo-pkgpath="):
			opts.pkgpath = args[0][13:]

		case strings.HasPrefix(args[0], "-fgo-relative-import-path="):
			// TODO(pcc): Handle this.

		case strings.HasPrefix(args[0], "-fstack-protector"):
			// TODO(axw) set ssp function attributes. This can be useful
			// even for Go, if it interfaces with code written in a non-
			// memory safe language (e.g. via cgo).

		case strings.HasPrefix(args[0], "-W"):
			// Go doesn't do warnings. Ignore.

		case args[0] == "-fload-plugin":
			if len(args) == 1 {
				return opts, errors.New("missing argument after '-fload-plugin'")
			}
			opts.plugins = append(opts.plugins, args[1])
			consumedArgs = 2

		case args[0] == "-fno-toplevel-reorder":
			// This is a GCC-specific code generation option. Ignore.

		case args[0] == "-emit-llvm":
			opts.emitIR = true

		case args[0] == "-flto":
			opts.lto = true

		case args[0] == "-fPIC":
			opts.pic = true

		case strings.HasPrefix(args[0], "-fsanitize-blacklist="):
			opts.sanitizer.blacklist = args[0][21:]

		// TODO(pcc): Enforce mutual exclusion between sanitizers.

		case args[0] == "-fsanitize=address":
			opts.sanitizer.address = true

		case args[0] == "-fsanitize=thread":
			opts.sanitizer.thread = true

		case args[0] == "-fsanitize=memory":
			opts.sanitizer.memory = true

		case args[0] == "-fsanitize=dataflow":
			opts.sanitizer.dataflow = true

		case args[0] == "-g":
			opts.generateDebug = true

		case args[0] == "-mllvm":
			if len(args) == 1 {
				return opts, errors.New("missing argument after '-mllvm'")
			}
			opts.llvmArgs = append(opts.llvmArgs, args[1])
			consumedArgs = 2

		case strings.HasPrefix(args[0], "-m"), args[0] == "-funsafe-math-optimizations", args[0] == "-ffp-contract=off":
			// TODO(pcc): Handle code generation options.

		case args[0] == "-no-prefix":
			noPrefix = true

		case args[0] == "-o":
			if len(args) == 1 {
				return opts, errors.New("missing argument after '-o'")
			}
			opts.output = args[1]
			consumedArgs = 2

		case args[0] == "-pie":
			opts.pieLink = true

		case args[0] == "-dumpversion",
			args[0] == "-print-libgcc-file-name",
			args[0] == "-print-multi-os-directory",
			args[0] == "--version":
			actionKind = actionPrint
			opts.output = args[0]

		case args[0] == "-static":
			opts.staticLink = true

		case args[0] == "-static-libgcc":
			opts.staticLibgcc = true

		case args[0] == "-static-libgo":
			opts.staticLibgo = true

		default:
			return opts, fmt.Errorf("unrecognized command line option '%s'", args[0])
		}

		args = args[consumedArgs:]
	}

	if actionKind != actionPrint && len(goInputs) == 0 && !hasOtherNonFlagInputs {
		return opts, errors.New("no input files")
	}

	if !noPrefix {
		opts.prefix, err = getInstPrefix()
		if err != nil {
			return opts, err
		}
	}

	if opts.sanitizer.crtPrefix == "" {
		opts.sanitizer.crtPrefix = opts.prefix
	}

	if opts.sanitizer.isPIEDefault() {
		// This should really only be turning on -fPIE, but this isn't
		// easy to do from Go, and -fPIC is a superset of it anyway.
		opts.pic = true
		opts.pieLink = true
	}

	switch actionKind {
	case actionLink:
		if len(goInputs) != 0 {
			opts.actions = []action{action{actionCompile, goInputs}}
		}
		opts.actions = append(opts.actions, action{actionLink, otherInputs})

	case actionCompile, actionAssemble:
		if len(goInputs) != 0 {
			opts.actions = []action{action{actionKind, goInputs}}
		}

	case actionPrint:
		opts.actions = []action{action{actionKind, nil}}
	}

	if opts.output == "" && len(opts.actions) != 0 {
		switch actionKind {
		case actionCompile, actionAssemble:
			base := filepath.Base(goInputs[0])
			base = base[0 : len(base)-3]
			if actionKind == actionCompile {
				opts.output = base + ".o"
			} else {
				opts.output = base + ".s"
			}

		case actionLink:
			opts.output = "a.out"
		}
	}

	return opts, nil
}