diff --git a/ChangeLog b/ChangeLog index 88702d7..67f302b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Sun May 10 20:24:13 2009 Minero Aoki + + * 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 * net/loveruby/cflat/compiler/IRGenerator.java: should not return diff --git a/net/loveruby/cflat/asm/Assembler.java b/net/loveruby/cflat/asm/AssemblyFile.java similarity index 98% rename from net/loveruby/cflat/asm/Assembler.java rename to net/loveruby/cflat/asm/AssemblyFile.java index 6bd5062..0f55b85 100644 --- a/net/loveruby/cflat/asm/Assembler.java +++ b/net/loveruby/cflat/asm/AssemblyFile.java @@ -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 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(); this.naturalType = naturalType; this.commentIndentLevel = 0; diff --git a/net/loveruby/cflat/compiler/CodeGenerator.java b/net/loveruby/cflat/compiler/CodeGenerator.java index 82ee44b..13d79cc 100644 --- a/net/loveruby/cflat/compiler/CodeGenerator.java +++ b/net/loveruby/cflat/compiler/CodeGenerator.java @@ -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, ELFConstants { // #@@range/ctor{ protected CodeGeneratorOptions options; + protected Platform platform; protected ErrorHandler errorHandler; - protected LinkedList asStack; - protected Assembler as; + protected LinkedList 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(); + this.asStack = new LinkedList(); } // #@@} @@ -27,7 +31,7 @@ public class CodeGenerator implements IRVisitor, 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, 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, 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, ELFConstants { AsmStatistics stats = AsmStatistics.collect(bodyAsms); bodyAsms = reduceLabels(bodyAsms, stats); List 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, 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,14 +570,8 @@ public class CodeGenerator implements IRVisitor, 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); - fixMemref((IndirectMemoryReference)var.memref(), -len); - } - else { - fixMemref((IndirectMemoryReference)var.memref(), len); - len = Assembler.align(len + var.allocSize(), stackAlignment); - } + len = platform.alignStack(len + var.allocSize()); + fixMemref((IndirectMemoryReference)var.memref(), -len); } // Allocate local variables in child scopes. // We allocate child scopes in the same area (overrapped). @@ -608,12 +593,7 @@ public class CodeGenerator implements IRVisitor, ELFConstants { // #@@range/extendStack{ protected void extendStack(long len) { if (len > 0) { - if (stackGrowsLower) { - as.sub(imm(len), sp()); - } - else { - as.add(imm(len), sp()); - } + as.sub(imm(len), sp()); } } // #@@} @@ -621,12 +601,7 @@ public class CodeGenerator implements IRVisitor, ELFConstants { // #@@range/rewindStack{ protected void rewindStack(long len) { if (len > 0) { - if (stackGrowsLower) { - as.add(imm(len), sp()); - } - else { - as.sub(imm(len), sp()); - } + as.add(imm(len), sp()); } } // #@@} @@ -649,18 +624,13 @@ public class CodeGenerator implements IRVisitor, ELFConstants { // #@@range/stackTop{ protected IndirectMemoryReference stackTop() { - if (stackGrowsLower) { - return mem(-stackPointer, bp()); - } - else { - return mem(stackPointer - stackWordSize, bp()); - } + return mem(-stackPointer, 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, 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, ELFConstants { // #@@range/fixTmpOffsets{ protected void fixTmpOffsets(List 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, ELFConstants { } // rewind stack // >4 bytes arguments are not supported. - rewindStack(node.numArgs() * stackWordSize); + rewindStack(platform.stackSizeFromWordNum(node.numArgs())); return null; } // #@@} diff --git a/net/loveruby/cflat/compiler/Compiler.java b/net/loveruby/cflat/compiler/Compiler.java index 324fd6f..0d54a41 100644 --- a/net/loveruby/cflat/compiler/Compiler.java +++ b/net/loveruby/cflat/compiler/Compiler.java @@ -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 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); } diff --git a/net/loveruby/cflat/compiler/Options.java b/net/loveruby/cflat/compiler/Options.java index 02619f3..6eddea9 100644 --- a/net/loveruby/cflat/compiler/Options.java +++ b/net/loveruby/cflat/compiler/Options.java @@ -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 asOptions; - protected boolean generatingSharedLibrary; - protected boolean generatingPIE; - protected List 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 asOptions = new ArrayList(); + boolean generatingSharedLibrary = false; + boolean generatingPIE = false; + List ldArgs = new ArrayList(); + 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(); - this.generatingSharedLibrary = false; - this.generatingPIE = false; - this.ldArgs = new ArrayList(); - } - - 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 sourceFiles() { + private List sourceFiles() { List result = new ArrayList(); 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 asOptions() { + List asOptions() { return this.asOptions; } - public boolean isGeneratingSharedLibrary() { + boolean isGeneratingSharedLibrary() { return this.generatingSharedLibrary; } - public boolean isGeneratingPIE() { + boolean isGeneratingPIE() { return this.generatingPIE; } - public List ldArgs() { + List ldArgs() { return this.ldArgs; } - public boolean noStartFiles() { + boolean noStartFiles() { return this.noStartFiles; } - public boolean noDefaultLibs() { + boolean noDefaultLibs() { return this.noDefaultLibs; } /** Returns List. */ - public List parse(List argsList) { + List parse(List argsList) { List srcs = new ArrayList(); ListIterator 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 srcs, List ldArgs, String sourceName) { + private void addSourceFile(List srcs, List 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 args) { + private String getOptArg(String opt, ListIterator 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 args) { + private String nextArg(String opt, ListIterator 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 parseCommaSeparatedOptions(String opt) { + private List parseCommaSeparatedOptions(String opt) { List 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."); diff --git a/net/loveruby/cflat/platform/Platform.java b/net/loveruby/cflat/platform/Platform.java new file mode 100644 index 0000000..dbb4654 --- /dev/null +++ b/net/loveruby/cflat/platform/Platform.java @@ -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); +} diff --git a/net/loveruby/cflat/platform/X86Linux.java b/net/loveruby/cflat/platform/X86Linux.java new file mode 100644 index 0000000..ed6f92d --- /dev/null +++ b/net/loveruby/cflat/platform/X86Linux.java @@ -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; + } +} diff --git a/net/loveruby/cflat/type/StructType.java b/net/loveruby/cflat/type/StructType.java index 070fd2c..bc8c367 100644 --- a/net/loveruby/cflat/type/StructType.java +++ b/net/loveruby/cflat/type/StructType.java @@ -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; } diff --git a/net/loveruby/cflat/type/UnionType.java b/net/loveruby/cflat/type/UnionType.java index 98b7b12..b8707f6 100644 --- a/net/loveruby/cflat/type/UnionType.java +++ b/net/loveruby/cflat/type/UnionType.java @@ -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; } diff --git a/net/loveruby/cflat/utils/AsmUtils.java b/net/loveruby/cflat/utils/AsmUtils.java new file mode 100644 index 0000000..ab7d493 --- /dev/null +++ b/net/loveruby/cflat/utils/AsmUtils.java @@ -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; + } +}