mirror of https://github.com/aamine/cbc
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:
parent
135881389d
commit
2bfba83992
35
ChangeLog
35
ChangeLog
|
@ -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>
|
||||
|
||||
* net/loveruby/cflat/asm/Assembler.java -> AssemblyFile.java
|
||||
|
|
|
@ -1,31 +1,15 @@
|
|||
package net.loveruby.cflat.asm;
|
||||
|
||||
public class Register extends AsmOperand {
|
||||
abstract public class Register extends AsmOperand {
|
||||
protected int size;
|
||||
protected String name;
|
||||
|
||||
// platform dependent
|
||||
static final protected int naturalSize = 4;
|
||||
|
||||
public Register(String name) {
|
||||
this(naturalSize, name);
|
||||
}
|
||||
|
||||
public Register(int size, String name) {
|
||||
this.size = size;
|
||||
this.name = 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());
|
||||
}
|
||||
}
|
||||
abstract public Register forType(Type t);
|
||||
|
||||
public boolean isRegister() {
|
||||
return true;
|
||||
|
@ -40,9 +24,7 @@ public class Register extends AsmOperand {
|
|||
return name.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* size difference does NOT matter.
|
||||
*/
|
||||
/** size difference does NOT matter. */
|
||||
public boolean equals(Register reg) {
|
||||
return name.equals(reg.baseName());
|
||||
}
|
||||
|
@ -51,36 +33,14 @@ public class Register extends AsmOperand {
|
|||
return name;
|
||||
}
|
||||
|
||||
// default implementation
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return name;
|
||||
}
|
||||
|
||||
public void collectStatistics(AsmStatistics stats) {
|
||||
stats.registerUsed(this);
|
||||
}
|
||||
|
||||
public String toSource(SymbolTable table) {
|
||||
return "%" + name();
|
||||
}
|
||||
abstract public String toSource(SymbolTable table);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package net.loveruby.cflat.compiler;
|
|||
import net.loveruby.cflat.asm.*;
|
||||
import java.util.*;
|
||||
|
||||
class CodeGeneratorOptions {
|
||||
public class CodeGeneratorOptions {
|
||||
protected int optimizeLevel;
|
||||
protected boolean generatePIC;
|
||||
protected boolean generatePIE;
|
||||
|
|
|
@ -212,8 +212,7 @@ public class Compiler {
|
|||
}
|
||||
|
||||
protected String generateAssembly(IR ir, Options opts) {
|
||||
CodeGenerator gen = new CodeGenerator(
|
||||
opts.genOptions(), opts.platform(), errorHandler);
|
||||
CodeGenerator gen = opts.codeGenerator(errorHandler);
|
||||
return gen.generate(ir);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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.asm.*;
|
||||
import net.loveruby.cflat.exception.*;
|
||||
|
@ -77,6 +77,10 @@ class Options {
|
|||
return platform.typeTable();
|
||||
}
|
||||
|
||||
CodeGenerator codeGenerator(ErrorHandler errorHandler) {
|
||||
return platform.codeGenerator(genOptions, errorHandler);
|
||||
}
|
||||
|
||||
LibraryLoader loader() {
|
||||
return this.loader;
|
||||
}
|
||||
|
@ -93,10 +97,6 @@ class Options {
|
|||
return this.debugParser;
|
||||
}
|
||||
|
||||
CodeGeneratorOptions genOptions() {
|
||||
return genOptions;
|
||||
}
|
||||
|
||||
List<String> asOptions() {
|
||||
return this.asOptions;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -78,11 +78,6 @@ public class IR {
|
|||
return constantTable;
|
||||
}
|
||||
|
||||
public net.loveruby.cflat.asm.Type naturalType() {
|
||||
// platform dependent!!!
|
||||
return Type.INT32;
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
dump(System.out);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 java.util.*;
|
||||
|
||||
|
@ -21,11 +22,7 @@ public class AssemblyFile {
|
|||
this.assemblies.addAll(assemblies);
|
||||
}
|
||||
|
||||
static final public String CODE_SYMBOL_BASE = ".L";
|
||||
static final public String CONST_SYMBOL_BASE = ".LC";
|
||||
|
||||
public String toSource() {
|
||||
SymbolTable symbolTable = new SymbolTable(CODE_SYMBOL_BASE);
|
||||
public String toSource(SymbolTable symbolTable) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (Assembly asm : assemblies) {
|
||||
buf.append(asm.toSource(symbolTable));
|
|
@ -1,15 +1,19 @@
|
|||
package net.loveruby.cflat.compiler;
|
||||
import net.loveruby.cflat.platform.Platform;
|
||||
package net.loveruby.cflat.sysdep.x86;
|
||||
import net.loveruby.cflat.compiler.CodeGeneratorOptions;
|
||||
import net.loveruby.cflat.compiler.ErrorHandler;
|
||||
import net.loveruby.cflat.ast.Location;
|
||||
import net.loveruby.cflat.entity.*;
|
||||
import net.loveruby.cflat.ir.*;
|
||||
import net.loveruby.cflat.asm.*;
|
||||
import net.loveruby.cflat.utils.AsmUtils;
|
||||
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{
|
||||
protected CodeGeneratorOptions options;
|
||||
protected Platform platform;
|
||||
protected ErrorHandler errorHandler;
|
||||
protected LinkedList<AssemblyFile> asStack;
|
||||
protected AssemblyFile as;
|
||||
|
@ -17,10 +21,8 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
protected Label epilogue;
|
||||
|
||||
public CodeGenerator(CodeGeneratorOptions options,
|
||||
Platform platform,
|
||||
ErrorHandler errorHandler) {
|
||||
this.options = options;
|
||||
this.platform = platform;
|
||||
this.errorHandler = errorHandler;
|
||||
this.asStack = new LinkedList<AssemblyFile>();
|
||||
}
|
||||
|
@ -28,10 +30,12 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
|
||||
/** Compiles IR and generates assembly code. */
|
||||
// #@@range/generate{
|
||||
static final private String CONST_SYMBOL_BASE = ".LC";
|
||||
static final private String LABEL_SYMBOL_BASE = ".L";
|
||||
|
||||
public String generate(IR ir) {
|
||||
this.naturalType = ir.naturalType();
|
||||
pushAssembler();
|
||||
SymbolTable constSymbols = new SymbolTable(AssemblyFile.CONST_SYMBOL_BASE);
|
||||
SymbolTable constSymbols = new SymbolTable(CONST_SYMBOL_BASE);
|
||||
for (ConstantEntry ent : ir.constantTable().entries()) {
|
||||
locateConstant(ent, constSymbols);
|
||||
}
|
||||
|
@ -42,11 +46,13 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
locateFunction(func);
|
||||
}
|
||||
compileIR(ir);
|
||||
return popAssembler().toSource();
|
||||
return popAssembler().toSource(new SymbolTable(LABEL_SYMBOL_BASE));
|
||||
}
|
||||
// #@@}
|
||||
|
||||
// #@@range/pushAssembler{
|
||||
static final private Type NATURAL_TYPE = Type.INT32;
|
||||
|
||||
protected void pushAssembler() {
|
||||
this.as = new AssemblyFile(naturalType);
|
||||
asStack.add(this.as);
|
||||
|
@ -226,14 +232,12 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
// #@@}
|
||||
|
||||
// #@@range/globalSymbol{
|
||||
// platform dependent
|
||||
protected Symbol globalSymbol(String sym) {
|
||||
return new NamedSymbol(sym);
|
||||
}
|
||||
// #@@}
|
||||
|
||||
// #@@range/privateSymbol{
|
||||
// platform dependent
|
||||
protected Symbol privateSymbol(String sym) {
|
||||
return new NamedSymbol(sym);
|
||||
}
|
||||
|
@ -351,6 +355,18 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
* ======================= 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. */
|
||||
// #@@range/compileFunction{
|
||||
public void compileFunction(DefinedFunction func) {
|
||||
|
@ -376,7 +392,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 = platform.stackSizeFromWordNum(saveRegs.size());
|
||||
long saveRegsBytes = stackSizeFromWordNum(saveRegs.size());
|
||||
long lvarBytes = allocateLocalVariables(
|
||||
func.body().scope(), saveRegsBytes);
|
||||
fixTmpOffsets(bodyAsms, saveRegsBytes + lvarBytes);
|
||||
|
@ -477,7 +493,6 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
|
||||
protected List<Register> calleeSavedRegistersCache = null;
|
||||
|
||||
// platform dependent
|
||||
protected List<Register> calleeSavedRegisters() {
|
||||
if (calleeSavedRegistersCache == null) {
|
||||
List<Register> regs = new ArrayList<Register>();
|
||||
|
@ -536,7 +551,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
protected void allocateParameters(DefinedFunction func) {
|
||||
long numWords = paramStartWordNum;
|
||||
for (Parameter var : func.parameters()) {
|
||||
var.setMemref(mem(platform.stackSizeFromWordNum(numWords), bp()));
|
||||
var.setMemref(mem(stackSizeFromWordNum(numWords), bp()));
|
||||
numWords++;
|
||||
}
|
||||
}
|
||||
|
@ -570,7 +585,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
protected long allocateScope(LocalScope scope, long parentStackLen) {
|
||||
long len = parentStackLen;
|
||||
for (DefinedVariable var : scope.localVariables()) {
|
||||
len = platform.alignStack(len + var.allocSize());
|
||||
len = alignStack(len + var.allocSize());
|
||||
fixMemref((IndirectMemoryReference)var.memref(), -len);
|
||||
}
|
||||
// Allocate local variables in child scopes.
|
||||
|
@ -630,7 +645,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
|
||||
// #@@range/virtualPush{
|
||||
protected void virtualPush(Register reg) {
|
||||
extendVirtualStack(platform.stackWordSize());
|
||||
extendVirtualStack(STACK_WORD_SIZE);
|
||||
as.relocatableMov(reg, stackTop());
|
||||
if (options.isVerboseAsm()) {
|
||||
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.relocatableMov(stackTop(), reg);
|
||||
rewindVirtualStack(platform.stackWordSize());
|
||||
rewindVirtualStack(STACK_WORD_SIZE);
|
||||
}
|
||||
// #@@}
|
||||
|
||||
|
@ -694,7 +709,7 @@ public class CodeGenerator implements IRVisitor<Void,Void>, ELFConstants {
|
|||
}
|
||||
// rewind stack
|
||||
// >4 bytes arguments are not supported.
|
||||
rewindStack(platform.stackSizeFromWordNum(node.numArgs()));
|
||||
rewindStack(stackSizeFromWordNum(node.numArgs()));
|
||||
return null;
|
||||
}
|
||||
// #@@}
|
|
@ -1,4 +1,4 @@
|
|||
package net.loveruby.cflat.asm;
|
||||
package net.loveruby.cflat.sysdep.x86;
|
||||
|
||||
public interface ELFConstants {
|
||||
// Flags
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue