r4811@macbookpro: aamine | 2009-05-10 22:41:42 +0900

* net/loveruby/cflat/sysdep/x86: new package.
 * net/loveruby/cflat/asm/ELFConstants.java -> net/loveruby/cflat/sysdep/x86
 * net/loveruby/cflat/asm/AssemblyFile.java -> net/loveruby/cflat/sysdep/x86
 net/loveruby/cflat/asm/Register.java
 * net/loveruby/cflat/platform/X86Linux.java -> net/loveruby/cflat/sysdep/x86
 * net/loveruby/cflat/compiler/CodeGenerator.java -> net/loveruby/cflat/sysdep/x86
 * net/loveruby/cflat/platform/Platform.java -> net/loveruby/cflat/compiler
 * net/loveruby/cflat/sysdep/x86/Register.java: new file.
 * net/loveruby/cflat/compiler/Options.java: new method #codeGenerator.
 * net/loveruby/cflat/compiler/Compiler.java: get CodeGenerator from Options.
 * net/loveruby/cflat/compiler/CodeGeneratorOptions.java: make public.
 * net/loveruby/cflat/ir/IR.java: now naturalType is useless (provided by CodeGenerator).
 


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4197 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2009-05-10 14:51:56 +00:00
parent 135881389d
commit 2bfba83992
14 changed files with 162 additions and 130 deletions

View File

@ -1,3 +1,38 @@
Sun May 10 22:42:07 2009 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/sysdep/x86: new package.
* net/loveruby/cflat/asm/ELFConstants.java ->
net/loveruby/cflat/sysdep/x86
* net/loveruby/cflat/asm/AssemblyFile.java ->
net/loveruby/cflat/sysdep/x86
net/loveruby/cflat/asm/Register.java
* net/loveruby/cflat/platform/X86Linux.java ->
net/loveruby/cflat/sysdep/x86
* net/loveruby/cflat/compiler/CodeGenerator.java ->
net/loveruby/cflat/sysdep/x86
* net/loveruby/cflat/platform/Platform.java ->
net/loveruby/cflat/compiler
* net/loveruby/cflat/sysdep/x86/Register.java: new file.
* net/loveruby/cflat/compiler/Options.java: new method
#codeGenerator.
* net/loveruby/cflat/compiler/Compiler.java: get CodeGenerator
from Options.
* net/loveruby/cflat/compiler/CodeGeneratorOptions.java: make
public.
* net/loveruby/cflat/ir/IR.java: now naturalType is useless
(provided by CodeGenerator).
Sun May 10 20:24:13 2009 Minero Aoki <aamine@loveruby.net> Sun May 10 20:24:13 2009 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/asm/Assembler.java -> AssemblyFile.java * net/loveruby/cflat/asm/Assembler.java -> AssemblyFile.java

View File

@ -1,31 +1,15 @@
package net.loveruby.cflat.asm; package net.loveruby.cflat.asm;
public class Register extends AsmOperand { abstract public class Register extends AsmOperand {
protected int size; protected int size;
protected String name; protected String name;
// platform dependent
static final protected int naturalSize = 4;
public Register(String name) {
this(naturalSize, name);
}
public Register(int size, String name) { public Register(int size, String name) {
this.size = size; this.size = size;
this.name = name; this.name = name;
} }
public Register forType(Type t) { abstract public Register forType(Type t);
switch (t.size()) {
case 1:
case 2:
case 4:
return new Register(t.size(), name);
default:
throw new Error("invalid register size: " + t.size());
}
}
public boolean isRegister() { public boolean isRegister() {
return true; return true;
@ -40,9 +24,7 @@ public class Register extends AsmOperand {
return name.hashCode(); return name.hashCode();
} }
/** /** size difference does NOT matter. */
* size difference does NOT matter.
*/
public boolean equals(Register reg) { public boolean equals(Register reg) {
return name.equals(reg.baseName()); return name.equals(reg.baseName());
} }
@ -51,36 +33,14 @@ public class Register extends AsmOperand {
return name; return name;
} }
// default implementation
public String name() { public String name() {
switch (size) { return name;
case 1: return lowerByteRegister(name);
case 2: return name;
case 4: return "e" + name;
default:
throw new Error("invalid register size: " + size);
}
}
protected String lowerByteRegister(String baseName) {
if (! hasLowerByteRegister(baseName)) {
throw new Error("does not have lower-byte register: " + baseName);
}
return baseName.substring(0, 1) + "l";
}
protected boolean hasLowerByteRegister(String baseName) {
if (baseName.equals("ax")) return true;
if (baseName.equals("bx")) return true;
if (baseName.equals("cx")) return true;
if (baseName.equals("dx")) return true;
return false;
} }
public void collectStatistics(AsmStatistics stats) { public void collectStatistics(AsmStatistics stats) {
stats.registerUsed(this); stats.registerUsed(this);
} }
public String toSource(SymbolTable table) { abstract public String toSource(SymbolTable table);
return "%" + name();
}
} }

View File

@ -2,7 +2,7 @@ package net.loveruby.cflat.compiler;
import net.loveruby.cflat.asm.*; import net.loveruby.cflat.asm.*;
import java.util.*; import java.util.*;
class CodeGeneratorOptions { public class CodeGeneratorOptions {
protected int optimizeLevel; protected int optimizeLevel;
protected boolean generatePIC; protected boolean generatePIC;
protected boolean generatePIE; protected boolean generatePIE;

View File

@ -212,8 +212,7 @@ public class Compiler {
} }
protected String generateAssembly(IR ir, Options opts) { protected String generateAssembly(IR ir, Options opts) {
CodeGenerator gen = new CodeGenerator( CodeGenerator gen = opts.codeGenerator(errorHandler);
opts.genOptions(), opts.platform(), errorHandler);
return gen.generate(ir); return gen.generate(ir);
} }

View File

@ -1,5 +1,5 @@
package net.loveruby.cflat.compiler; package net.loveruby.cflat.compiler;
import net.loveruby.cflat.platform.*; import net.loveruby.cflat.sysdep.x86.X86Linux;
import net.loveruby.cflat.type.TypeTable; import net.loveruby.cflat.type.TypeTable;
import net.loveruby.cflat.asm.*; import net.loveruby.cflat.asm.*;
import net.loveruby.cflat.exception.*; import net.loveruby.cflat.exception.*;
@ -77,6 +77,10 @@ class Options {
return platform.typeTable(); return platform.typeTable();
} }
CodeGenerator codeGenerator(ErrorHandler errorHandler) {
return platform.codeGenerator(genOptions, errorHandler);
}
LibraryLoader loader() { LibraryLoader loader() {
return this.loader; return this.loader;
} }
@ -93,10 +97,6 @@ class Options {
return this.debugParser; return this.debugParser;
} }
CodeGeneratorOptions genOptions() {
return genOptions;
}
List<String> asOptions() { List<String> asOptions() {
return this.asOptions; return this.asOptions;
} }

View File

@ -0,0 +1,7 @@
package net.loveruby.cflat.compiler;
import net.loveruby.cflat.type.TypeTable;
public interface Platform {
TypeTable typeTable();
CodeGenerator codeGenerator(CodeGeneratorOptions opts, ErrorHandler h);
}

View File

@ -78,11 +78,6 @@ public class IR {
return constantTable; return constantTable;
} }
public net.loveruby.cflat.asm.Type naturalType() {
// platform dependent!!!
return Type.INT32;
}
public void dump() { public void dump() {
dump(System.out); dump(System.out);
} }

View File

@ -1,10 +0,0 @@
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

@ -1,36 +0,0 @@
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,4 +1,5 @@
package net.loveruby.cflat.asm; package net.loveruby.cflat.sysdep.x86;
import net.loveruby.cflat.asm.*;
import net.loveruby.cflat.utils.*; import net.loveruby.cflat.utils.*;
import java.util.*; import java.util.*;
@ -21,11 +22,7 @@ public class AssemblyFile {
this.assemblies.addAll(assemblies); this.assemblies.addAll(assemblies);
} }
static final public String CODE_SYMBOL_BASE = ".L"; public String toSource(SymbolTable symbolTable) {
static final public String CONST_SYMBOL_BASE = ".LC";
public String toSource() {
SymbolTable symbolTable = new SymbolTable(CODE_SYMBOL_BASE);
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
for (Assembly asm : assemblies) { for (Assembly asm : assemblies) {
buf.append(asm.toSource(symbolTable)); buf.append(asm.toSource(symbolTable));

View File

@ -1,15 +1,19 @@
package net.loveruby.cflat.compiler; package net.loveruby.cflat.sysdep.x86;
import net.loveruby.cflat.platform.Platform; import net.loveruby.cflat.compiler.CodeGeneratorOptions;
import net.loveruby.cflat.compiler.ErrorHandler;
import net.loveruby.cflat.ast.Location; import net.loveruby.cflat.ast.Location;
import net.loveruby.cflat.entity.*; import net.loveruby.cflat.entity.*;
import net.loveruby.cflat.ir.*; import net.loveruby.cflat.ir.*;
import net.loveruby.cflat.asm.*; import net.loveruby.cflat.asm.*;
import net.loveruby.cflat.utils.AsmUtils;
import java.util.*; import java.util.*;
public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants { public class CodeGenerator
implements net.loveruby.cflat.compiler.CodeGenerator,
IRVisitor<Void,Void>,
ELFConstants {
// #@@range/ctor{ // #@@range/ctor{
protected CodeGeneratorOptions options; protected CodeGeneratorOptions options;
protected Platform platform;
protected ErrorHandler errorHandler; protected ErrorHandler errorHandler;
protected LinkedList<AssemblyFile> asStack; protected LinkedList<AssemblyFile> asStack;
protected AssemblyFile as; protected AssemblyFile as;
@ -17,10 +21,8 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
protected Label epilogue; protected Label epilogue;
public CodeGenerator(CodeGeneratorOptions options, public CodeGenerator(CodeGeneratorOptions options,
Platform platform,
ErrorHandler errorHandler) { ErrorHandler errorHandler) {
this.options = options; this.options = options;
this.platform = platform;
this.errorHandler = errorHandler; this.errorHandler = errorHandler;
this.asStack = new LinkedList<AssemblyFile>(); this.asStack = new LinkedList<AssemblyFile>();
} }
@ -28,10 +30,12 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
/** Compiles IR and generates assembly code. */ /** Compiles IR and generates assembly code. */
// #@@range/generate{ // #@@range/generate{
static final private String CONST_SYMBOL_BASE = ".LC";
static final private String LABEL_SYMBOL_BASE = ".L";
public String generate(IR ir) { public String generate(IR ir) {
this.naturalType = ir.naturalType();
pushAssembler(); pushAssembler();
SymbolTable constSymbols = new SymbolTable(AssemblyFile.CONST_SYMBOL_BASE); SymbolTable constSymbols = new SymbolTable(CONST_SYMBOL_BASE);
for (ConstantEntry ent : ir.constantTable().entries()) { for (ConstantEntry ent : ir.constantTable().entries()) {
locateConstant(ent, constSymbols); locateConstant(ent, constSymbols);
} }
@ -42,11 +46,13 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
locateFunction(func); locateFunction(func);
} }
compileIR(ir); compileIR(ir);
return popAssembler().toSource(); return popAssembler().toSource(new SymbolTable(LABEL_SYMBOL_BASE));
} }
// #@@} // #@@}
// #@@range/pushAssembler{ // #@@range/pushAssembler{
static final private Type NATURAL_TYPE = Type.INT32;
protected void pushAssembler() { protected void pushAssembler() {
this.as = new AssemblyFile(naturalType); this.as = new AssemblyFile(naturalType);
asStack.add(this.as); asStack.add(this.as);
@ -226,14 +232,12 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
// #@@} // #@@}
// #@@range/globalSymbol{ // #@@range/globalSymbol{
// platform dependent
protected Symbol globalSymbol(String sym) { protected Symbol globalSymbol(String sym) {
return new NamedSymbol(sym); return new NamedSymbol(sym);
} }
// #@@} // #@@}
// #@@range/privateSymbol{ // #@@range/privateSymbol{
// platform dependent
protected Symbol privateSymbol(String sym) { protected Symbol privateSymbol(String sym) {
return new NamedSymbol(sym); return new NamedSymbol(sym);
} }
@ -351,6 +355,18 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
* ======================= stack bottom * ======================= stack bottom
*/ */
// #@@range/stackParams{
static final private long STACK_WORD_SIZE = 4;
// #@@}
public long alignStack(long size) {
return AsmUtils.align(size, STACK_WORD_SIZE);
}
public long stackSizeFromWordNum(long numWords) {
return numWords * STACK_WORD_SIZE;
}
/** Compiles a function. */ /** Compiles a function. */
// #@@range/compileFunction{ // #@@range/compileFunction{
public void compileFunction(DefinedFunction func) { public void compileFunction(DefinedFunction func) {
@ -376,7 +392,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
AsmStatistics stats = AsmStatistics.collect(bodyAsms); AsmStatistics stats = AsmStatistics.collect(bodyAsms);
bodyAsms = reduceLabels(bodyAsms, stats); bodyAsms = reduceLabels(bodyAsms, stats);
List<Register> saveRegs = usedCalleeSavedRegistersWithoutBP(stats); List<Register> saveRegs = usedCalleeSavedRegistersWithoutBP(stats);
long saveRegsBytes = platform.stackSizeFromWordNum(saveRegs.size()); long saveRegsBytes = stackSizeFromWordNum(saveRegs.size());
long lvarBytes = allocateLocalVariables( long lvarBytes = allocateLocalVariables(
func.body().scope(), saveRegsBytes); func.body().scope(), saveRegsBytes);
fixTmpOffsets(bodyAsms, saveRegsBytes + lvarBytes); fixTmpOffsets(bodyAsms, saveRegsBytes + lvarBytes);
@ -477,7 +493,6 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
protected List<Register> calleeSavedRegistersCache = null; protected List<Register> calleeSavedRegistersCache = null;
// platform dependent
protected List<Register> calleeSavedRegisters() { protected List<Register> calleeSavedRegisters() {
if (calleeSavedRegistersCache == null) { if (calleeSavedRegistersCache == null) {
List<Register> regs = new ArrayList<Register>(); List<Register> regs = new ArrayList<Register>();
@ -536,7 +551,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
protected void allocateParameters(DefinedFunction func) { protected void allocateParameters(DefinedFunction func) {
long numWords = paramStartWordNum; long numWords = paramStartWordNum;
for (Parameter var : func.parameters()) { for (Parameter var : func.parameters()) {
var.setMemref(mem(platform.stackSizeFromWordNum(numWords), bp())); var.setMemref(mem(stackSizeFromWordNum(numWords), bp()));
numWords++; numWords++;
} }
} }
@ -570,7 +585,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
protected long allocateScope(LocalScope scope, long parentStackLen) { protected long allocateScope(LocalScope scope, long parentStackLen) {
long len = parentStackLen; long len = parentStackLen;
for (DefinedVariable var : scope.localVariables()) { for (DefinedVariable var : scope.localVariables()) {
len = platform.alignStack(len + var.allocSize()); len = alignStack(len + var.allocSize());
fixMemref((IndirectMemoryReference)var.memref(), -len); fixMemref((IndirectMemoryReference)var.memref(), -len);
} }
// Allocate local variables in child scopes. // Allocate local variables in child scopes.
@ -630,7 +645,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
// #@@range/virtualPush{ // #@@range/virtualPush{
protected void virtualPush(Register reg) { protected void virtualPush(Register reg) {
extendVirtualStack(platform.stackWordSize()); extendVirtualStack(STACK_WORD_SIZE);
as.relocatableMov(reg, stackTop()); as.relocatableMov(reg, stackTop());
if (options.isVerboseAsm()) { if (options.isVerboseAsm()) {
as.comment("push " + reg.name() + " -> " + stackTop()); as.comment("push " + reg.name() + " -> " + stackTop());
@ -644,7 +659,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
as.comment("pop " + reg.name() + " <- " + stackTop()); as.comment("pop " + reg.name() + " <- " + stackTop());
} }
as.relocatableMov(stackTop(), reg); as.relocatableMov(stackTop(), reg);
rewindVirtualStack(platform.stackWordSize()); rewindVirtualStack(STACK_WORD_SIZE);
} }
// #@@} // #@@}
@ -694,7 +709,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
} }
// rewind stack // rewind stack
// >4 bytes arguments are not supported. // >4 bytes arguments are not supported.
rewindStack(platform.stackSizeFromWordNum(node.numArgs())); rewindStack(stackSizeFromWordNum(node.numArgs()));
return null; return null;
} }
// #@@} // #@@}

View File

@ -1,4 +1,4 @@
package net.loveruby.cflat.asm; package net.loveruby.cflat.sysdep.x86;
public interface ELFConstants { public interface ELFConstants {
// Flags // Flags

View File

@ -0,0 +1,54 @@
package net.loveruby.cflat.sysdep.x86;
import net.loveruby.cflat.asm.*;
public class Register extends net.loveruby.cflat.asm.Register {
static final private int naturalSize = 4;
public Register(String name) {
super(naturalSize, name);
}
public Register(int size, String name) {
super(size, name);
}
public Register forType(Type t) {
switch (t.size()) {
case 1:
case 2:
case 4:
return new Register(t.size(), name);
default:
throw new Error("invalid register size: " + t.size());
}
}
public String name() {
switch (size) {
case 1: return lowerByteRegister(name);
case 2: return name;
case 4: return "e" + name;
default:
throw new Error("invalid register size: " + size);
}
}
private String lowerByteRegister(String baseName) {
if (! hasLowerByteRegister(baseName)) {
throw new Error("does not have lower-byte register: " + baseName);
}
return baseName.substring(0, 1) + "l";
}
private boolean hasLowerByteRegister(String baseName) {
if (baseName.equals("ax")) return true;
if (baseName.equals("bx")) return true;
if (baseName.equals("cx")) return true;
if (baseName.equals("dx")) return true;
return false;
}
public String toSource(SymbolTable table) {
return "%" + name();
}
}

View File

@ -0,0 +1,16 @@
package net.loveruby.cflat.sysdep.x86;
import net.loveruby.cflat.compiler.Platform;
import net.loveruby.cflat.compiler.CodeGeneratorOptions;
import net.loveruby.cflat.compiler.ErrorHandler;
import net.loveruby.cflat.type.TypeTable;
public class X86Linux implements Platform {
public TypeTable typeTable() {
return TypeTable.ilp32();
}
public CodeGenerator codeGenerator(
CodeGeneratorOptions opts, ErrorHandler h) {
return new CodeGenerator(opts, h);
}
}