r4808@macbookpro: aamine | 2009-05-10 20:23:48 +0900

* net/loveruby/cflat/asm/Assembler.java -> AssemblyFile.java
 * net/loveruby/cflat/utils/AsmUtils.java: split #align from AssemblyFile.
 * net/loveruby/cflat/type/StructType.java: use it.
 * net/loveruby/cflat/type/UnionType.java: use it.
 * net/loveruby/cflat/platform: new package to extract platform dependent operations.
 * net/loveruby/cflat/compiler/Compiler.java: use it.
 * net/loveruby/cflat/compiler/CodeGenerator.java: use it.
 * net/loveruby/cflat/compiler/Options.java: provide Platform object.
 


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4194 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2009-05-10 14:51:53 +00:00
parent 6e8bfed7a3
commit 2e1cbdaf66
10 changed files with 158 additions and 126 deletions

View File

@ -1,3 +1,24 @@
Sun May 10 20:24:13 2009 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/asm/Assembler.java -> AssemblyFile.java
* net/loveruby/cflat/utils/AsmUtils.java: split #align from
AssemblyFile.
* net/loveruby/cflat/type/StructType.java: use it.
* net/loveruby/cflat/type/UnionType.java: use it.
* net/loveruby/cflat/platform: new package to extract platform
dependent operations.
* net/loveruby/cflat/compiler/Compiler.java: use it.
* net/loveruby/cflat/compiler/CodeGenerator.java: use it.
* net/loveruby/cflat/compiler/Options.java: provide Platform
object.
Thu May 7 13:00:09 2009 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/IRGenerator.java: should not return

View File

@ -2,16 +2,12 @@ package net.loveruby.cflat.asm;
import net.loveruby.cflat.utils.*;
import java.util.*;
public class Assembler {
public class AssemblyFile {
protected List<Assembly> assemblies;
protected Type naturalType;
protected int commentIndentLevel;
static public long align(long n, long alignment) {
return (n + alignment - 1) / alignment * alignment;
}
public Assembler(Type naturalType) {
public AssemblyFile(Type naturalType) {
this.assemblies = new ArrayList<Assembly>();
this.naturalType = naturalType;
this.commentIndentLevel = 0;

View File

@ -1,4 +1,5 @@
package net.loveruby.cflat.compiler;
import net.loveruby.cflat.platform.Platform;
import net.loveruby.cflat.ast.Location;
import net.loveruby.cflat.entity.*;
import net.loveruby.cflat.ir.*;
@ -8,17 +9,20 @@ import java.util.*;
public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
// #@@range/ctor{
protected CodeGeneratorOptions options;
protected Platform platform;
protected ErrorHandler errorHandler;
protected LinkedList<Assembler> asStack;
protected Assembler as;
protected LinkedList<AssemblyFile> asStack;
protected AssemblyFile as;
protected Type naturalType;
protected Label epilogue;
public CodeGenerator(CodeGeneratorOptions options,
Platform platform,
ErrorHandler errorHandler) {
this.options = options;
this.platform = platform;
this.errorHandler = errorHandler;
this.asStack = new LinkedList<Assembler>();
this.asStack = new LinkedList<AssemblyFile>();
}
// #@@}
@ -27,7 +31,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
public String generate(IR ir) {
this.naturalType = ir.naturalType();
pushAssembler();
SymbolTable constSymbols = new SymbolTable(Assembler.CONST_SYMBOL_BASE);
SymbolTable constSymbols = new SymbolTable(AssemblyFile.CONST_SYMBOL_BASE);
for (ConstantEntry ent : ir.constantTable().entries()) {
locateConstant(ent, constSymbols);
}
@ -44,14 +48,14 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
// #@@range/pushAssembler{
protected void pushAssembler() {
this.as = new Assembler(naturalType);
this.as = new AssemblyFile(naturalType);
asStack.add(this.as);
}
// #@@}
// #@@range/popAssembler{
protected Assembler popAssembler() {
Assembler popped = asStack.removeLast();
protected AssemblyFile popAssembler() {
AssemblyFile popped = asStack.removeLast();
this.as = asStack.isEmpty() ? null : asStack.getLast();
return popped;
}
@ -347,17 +351,6 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
* ======================= stack bottom
*/
/*
* Platform Dependent Stack Parameters
*/
// #@@range/stackParams{
static final protected boolean stackGrowsLower = true;
static final protected long stackWordSize = 4;
static final protected long stackAlignment = stackWordSize;
static final protected long paramStartWord = 2;
// return addr and saved bp
// #@@}
/** Compiles a function. */
// #@@range/compileFunction{
public void compileFunction(DefinedFunction func) {
@ -383,7 +376,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
AsmStatistics stats = AsmStatistics.collect(bodyAsms);
bodyAsms = reduceLabels(bodyAsms, stats);
List<Register> saveRegs = usedCalleeSavedRegistersWithoutBP(stats);
long saveRegsBytes = saveRegs.size() * stackWordSize;
long saveRegsBytes = platform.stackSizeFromWordNum(saveRegs.size());
long lvarBytes = allocateLocalVariables(
func.body().scope(), saveRegsBytes);
fixTmpOffsets(bodyAsms, saveRegsBytes + lvarBytes);
@ -537,16 +530,14 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
// #@@}
// #@@range/allocateParameters{
static final private long paramStartWordNum = 2;
// return addr and saved bp
protected void allocateParameters(DefinedFunction func) {
long word = paramStartWord;
long numWords = paramStartWordNum;
for (Parameter var : func.parameters()) {
if (stackGrowsLower) {
var.setMemref(mem(word * stackWordSize, bp()));
}
else {
throw new Error("unsupported stack layout");
}
word++;
var.setMemref(mem(platform.stackSizeFromWordNum(numWords), bp()));
numWords++;
}
}
// #@@}
@ -579,15 +570,9 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
protected long allocateScope(LocalScope scope, long parentStackLen) {
long len = parentStackLen;
for (DefinedVariable var : scope.localVariables()) {
if (stackGrowsLower) {
len = Assembler.align(len + var.allocSize(), stackAlignment);
len = platform.alignStack(len + var.allocSize());
fixMemref((IndirectMemoryReference)var.memref(), -len);
}
else {
fixMemref((IndirectMemoryReference)var.memref(), len);
len = Assembler.align(len + var.allocSize(), stackAlignment);
}
}
// Allocate local variables in child scopes.
// We allocate child scopes in the same area (overrapped).
long maxLen = len;
@ -608,26 +593,16 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
// #@@range/extendStack{
protected void extendStack(long len) {
if (len > 0) {
if (stackGrowsLower) {
as.sub(imm(len), sp());
}
else {
as.add(imm(len), sp());
}
}
}
// #@@}
// #@@range/rewindStack{
protected void rewindStack(long len) {
if (len > 0) {
if (stackGrowsLower) {
as.add(imm(len), sp());
}
else {
as.sub(imm(len), sp());
}
}
}
// #@@}
@ -649,18 +624,13 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
// #@@range/stackTop{
protected IndirectMemoryReference stackTop() {
if (stackGrowsLower) {
return mem(-stackPointer, bp());
}
else {
return mem(stackPointer - stackWordSize, bp());
}
}
// #@@}
// #@@range/virtualPush{
protected void virtualPush(Register reg) {
extendVirtualStack(stackWordSize);
extendVirtualStack(platform.stackWordSize());
as.relocatableMov(reg, stackTop());
if (options.isVerboseAsm()) {
as.comment("push " + reg.name() + " -> " + stackTop());
@ -674,7 +644,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
as.comment("pop " + reg.name() + " <- " + stackTop());
}
as.relocatableMov(stackTop(), reg);
rewindVirtualStack(stackWordSize);
rewindVirtualStack(platform.stackWordSize());
}
// #@@}
@ -694,7 +664,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
// #@@range/fixTmpOffsets{
protected void fixTmpOffsets(List<Assembly> asms, long offset) {
for (Assembly asm : asms) {
asm.fixStackOffset(offset * (stackGrowsLower ? -1 : 1));
asm.fixStackOffset(-offset);
}
}
// #@@}
@ -724,7 +694,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
}
// rewind stack
// >4 bytes arguments are not supported.
rewindStack(node.numArgs() * stackWordSize);
rewindStack(platform.stackSizeFromWordNum(node.numArgs()));
return null;
}
// #@@}

View File

@ -25,12 +25,8 @@ public class Compiler {
}
// #@@}
private TypeTable defaultTypeTable() {
return TypeTable.ilp32();
}
public void commandMain(String[] origArgs) {
Options opts = new Options(defaultTypeTable(), new LibraryLoader());
Options opts = new Options();
List<SourceFile> srcs = null;
try {
srcs = opts.parse(Arrays.asList(origArgs));
@ -118,7 +114,7 @@ public class Compiler {
findExpr(ast).dump();
return;
}
ast.setTypeTable(opts.typeTable);
ast.setTypeTable(opts.typeTable());
semanticAnalysis(ast, opts);
switch (opts.mode()) {
case DumpReference:
@ -216,7 +212,8 @@ public class Compiler {
}
protected String generateAssembly(IR ir, Options opts) {
CodeGenerator gen = new CodeGenerator(opts.genOptions(), errorHandler);
CodeGenerator gen = new CodeGenerator(
opts.genOptions(), opts.platform(), errorHandler);
return gen.generate(ir);
}

View File

@ -1,4 +1,5 @@
package net.loveruby.cflat.compiler;
import net.loveruby.cflat.platform.*;
import net.loveruby.cflat.type.TypeTable;
import net.loveruby.cflat.asm.*;
import net.loveruby.cflat.exception.*;
@ -7,55 +8,45 @@ import java.io.*;
// package scope
class Options {
protected CompilerMode mode;
protected TypeTable typeTable;
protected LibraryLoader loader;
protected String outputFileName;
protected boolean verbose;
protected boolean debugParser;
protected CodeGeneratorOptions genOptions;
protected List<String> asOptions;
protected boolean generatingSharedLibrary;
protected boolean generatingPIE;
protected List<LdArg> ldArgs;
protected boolean noStartFiles = false;
protected boolean noDefaultLibs = false;
CompilerMode mode;
LibraryLoader loader = new LibraryLoader();
Platform platform = new X86Linux();
String outputFileName;
boolean verbose = false;
boolean debugParser = false;
CodeGeneratorOptions genOptions = new CodeGeneratorOptions();
List<String> asOptions = new ArrayList<String>();
boolean generatingSharedLibrary = false;
boolean generatingPIE = false;
List<LdArg> ldArgs = new ArrayList<LdArg>();
boolean noStartFiles = false;
boolean noDefaultLibs = false;
public Options(TypeTable typeTable, LibraryLoader loader) {
this.typeTable = typeTable;
this.loader = loader;
this.genOptions = new CodeGeneratorOptions();
this.asOptions = new ArrayList<String>();
this.generatingSharedLibrary = false;
this.generatingPIE = false;
this.ldArgs = new ArrayList<LdArg>();
}
public CompilerMode mode() {
CompilerMode mode() {
return mode;
}
public boolean isAssembleRequired() {
boolean isAssembleRequired() {
return mode.requires(CompilerMode.Assemble);
}
public boolean isLinkRequired() {
boolean isLinkRequired() {
return mode.requires(CompilerMode.Link);
}
public String outputFileNameFor(CompilerMode mode) {
String outputFileNameFor(CompilerMode mode) {
return this.mode == mode ? outputFileName : null;
}
public String exeFileName() {
String exeFileName() {
return getOutputFileName("");
}
public String soFileName() {
String soFileName() {
return getOutputFileName(".so");
}
protected String getOutputFileName(String newExt) {
private String getOutputFileName(String newExt) {
if (outputFileName != null) {
return outputFileName;
}
@ -68,7 +59,7 @@ class Options {
}
}
protected List<SourceFile> sourceFiles() {
private List<SourceFile> sourceFiles() {
List<SourceFile> result = new ArrayList<SourceFile>();
for (LdArg arg : ldArgs) {
if (arg.isSourceFile()) {
@ -78,56 +69,60 @@ class Options {
return result;
}
public TypeTable typeTable() {
return this.typeTable;
Platform platform() {
return platform;
}
public LibraryLoader loader() {
TypeTable typeTable() {
return platform.typeTable();
}
LibraryLoader loader() {
return this.loader;
}
public String outputFileName() {
String outputFileName() {
return this.outputFileName;
}
public boolean isVerboseMode() {
boolean isVerboseMode() {
return this.verbose;
}
public boolean doesDebugParser() {
boolean doesDebugParser() {
return this.debugParser;
}
public CodeGeneratorOptions genOptions() {
CodeGeneratorOptions genOptions() {
return genOptions;
}
public List<String> asOptions() {
List<String> asOptions() {
return this.asOptions;
}
public boolean isGeneratingSharedLibrary() {
boolean isGeneratingSharedLibrary() {
return this.generatingSharedLibrary;
}
public boolean isGeneratingPIE() {
boolean isGeneratingPIE() {
return this.generatingPIE;
}
public List<LdArg> ldArgs() {
List<LdArg> ldArgs() {
return this.ldArgs;
}
public boolean noStartFiles() {
boolean noStartFiles() {
return this.noStartFiles;
}
public boolean noDefaultLibs() {
boolean noDefaultLibs() {
return this.noDefaultLibs;
}
/** Returns List<SourceFile>. */
public List<SourceFile> parse(List<String> argsList) {
List<SourceFile> parse(List<String> argsList) {
List<SourceFile> srcs = new ArrayList<SourceFile>();
ListIterator<String> args = argsList.listIterator();
while (args.hasNext()) {
@ -253,18 +248,18 @@ class Options {
return srcs;
}
protected void parseError(String msg) {
private void parseError(String msg) {
throw new OptionParseError(msg);
}
protected void addSourceFile(List<SourceFile> srcs, List<LdArg> ldArgs, String sourceName) {
private void addSourceFile(List<SourceFile> srcs, List<LdArg> ldArgs, String sourceName) {
SourceFile src = new SourceFile(sourceName);
srcs.add(src);
// Original argument order does matter when linking.
ldArgs.add(src);
}
protected String getOptArg(String opt, ListIterator<String> args) {
private String getOptArg(String opt, ListIterator<String> args) {
String path = opt.substring(2);
if (path.length() != 0) { // -Ipath
return path;
@ -274,7 +269,7 @@ class Options {
}
}
protected String nextArg(String opt, ListIterator<String> args) {
private String nextArg(String opt, ListIterator<String> args) {
if (! args.hasNext()) {
parseError("missing argument for " + opt);
}
@ -282,7 +277,7 @@ class Options {
}
/** "-Wl,-rpath,/usr/local/lib" -> ["-rpath", "/usr/local/lib"] */
protected List<String> parseCommaSeparatedOptions(String opt) {
private List<String> parseCommaSeparatedOptions(String opt) {
List<String> opts = Arrays.asList(opt.split(","));
opts.remove(0); // remove "-Wl" etc.
if (opts.isEmpty()) {
@ -291,7 +286,7 @@ class Options {
return opts;
}
public void printUsage(PrintStream out) {
void printUsage(PrintStream out) {
out.println("Usage: cbc [options] file...");
out.println("Global Options:");
out.println(" --check-syntax Checks syntax and quit.");

View File

@ -0,0 +1,10 @@
package net.loveruby.cflat.platform;
public interface Platform {
net.loveruby.cflat.type.TypeTable typeTable();
net.loveruby.cflat.asm.Type naturalType();
long align(long size);
long stackWordSize();
long alignStack(long size);
long stackSizeFromWordNum(long numWords);
}

View File

@ -0,0 +1,36 @@
package net.loveruby.cflat.platform;
import net.loveruby.cflat.type.TypeTable;
import net.loveruby.cflat.asm.Type;
import net.loveruby.cflat.utils.AsmUtils;
public class X86Linux implements Platform {
static final Type naturalType = Type.INT32;
static final long alignment = 4;
// #@@range/stackParams{
static final long stackWordSize = 4;
// #@@}
public TypeTable typeTable() {
return TypeTable.ilp32();
}
public Type naturalType() {
return naturalType;
}
public long align(long size) {
return AsmUtils.align(size, alignment);
}
public long stackWordSize() {
return stackWordSize;
}
public long alignStack(long size) {
return AsmUtils.align(size, stackWordSize);
}
public long stackSizeFromWordNum(long num) {
return num * stackWordSize;
}
}

View File

@ -1,7 +1,7 @@
package net.loveruby.cflat.type;
import net.loveruby.cflat.ast.Slot;
import net.loveruby.cflat.ast.Location;
import net.loveruby.cflat.asm.Assembler;
import net.loveruby.cflat.utils.AsmUtils;
import java.util.*;
public class StructType extends CompositeType {
@ -20,12 +20,12 @@ public class StructType extends CompositeType {
long offset = 0;
long maxAlign = 1;
for (Slot s : members()) {
offset = Assembler.align(offset, s.allocSize());
offset = AsmUtils.align(offset, s.allocSize());
s.setOffset(offset);
offset += s.allocSize();
maxAlign = Math.max(maxAlign, s.alignment());
}
cachedSize = Assembler.align(offset, maxAlign);
cachedSize = AsmUtils.align(offset, maxAlign);
cachedAlign = maxAlign;
}

View File

@ -1,7 +1,7 @@
package net.loveruby.cflat.type;
import net.loveruby.cflat.ast.Slot;
import net.loveruby.cflat.ast.Location;
import net.loveruby.cflat.asm.Assembler;
import net.loveruby.cflat.utils.AsmUtils;
import java.util.*;
public class UnionType extends CompositeType {
@ -24,7 +24,7 @@ public class UnionType extends CompositeType {
maxSize = Math.max(maxSize, s.allocSize());
maxAlign = Math.max(maxAlign, s.alignment());
}
cachedSize = Assembler.align(maxSize, maxAlign);
cachedSize = AsmUtils.align(maxSize, maxAlign);
cachedAlign = maxAlign;
}

View File

@ -0,0 +1,7 @@
package net.loveruby.cflat.utils;
public abstract class AsmUtils {
static public long align(long n, long alignment) {
return (n + alignment - 1) / alignment * alignment;
}
}