* implement PIC generation.

* lib/Makefile: should generate PIC for libcbc.o.
* net/loveruby/cflat/compiler/Compiler.java: pass CodeGeneratorOptions to CodeGenerator.
* net/loveruby/cflat/compiler/Options.java: new options -fpic, -fPIC.
* net/loveruby/cflat/compiler/CodeGenerator.java: use position independent address for global variables, common symbols, defined/undefined functions and string constants.
* net/loveruby/cflat/compiler/CodeGeneratorOptions.java: new class.
* net/loveruby/cflat/asm/ELFConstants.java: new interface to define ELF-related constants.
* net/loveruby/cflat/asm/Assembler.java: new method #hidden.
* net/loveruby/cflat/asm/Assembler.java: new overload #section(s,s,s,s,s).
* net/loveruby/cflat/asm/IndirectMemoryReference.java: offset may not long, but Literal.
* net/loveruby/cflat/asm/Literal.java: new method #isZero.
* net/loveruby/cflat/asm/IntegerLiteral.java: ditto.
* net/loveruby/cflat/asm/LabelRef.java: ditto.
* net/loveruby/cflat/ast/ExprNode.java: new method #shouldEvaluatedToAddres.
* net/loveruby/cflat/ast/VariableNode.java: override it.
* net/loveruby/cflat/ast/CastNode.java: override it.
* net/loveruby/cflat/ast/Entity.java: new method #cannotLoad, to implement #shouldEvaluatedToAddress.
* net/loveruby/cflat/ast/Variable.java: override it.
* net/loveruby/cflat/ast/Function.java: override it.
* net/loveruby/cflat/ast/ExprNode.java: rename method: #AsmLiteral -> #AsmValue because it now returns ImmediateValue instead of Literal.
* net/loveruby/cflat/ast/CastNode.java: override it.
* net/loveruby/cflat/ast/LiteralNode.java: rename method also.
* net/loveruby/cflat/ast/IntegerLiteralNode.java: ditto.
* net/loveruby/cflat/ast/StringLiteralNode.java: ditto.
* net/loveruby/cflat/ast/Variable.java: holds memref and address here, not in subclasses.
* net/loveruby/cflat/ast/DefinedVariable.java: ditto.
* net/loveruby/cflat/ast/UndefinedVariable.java: ditto.
* net/loveruby/cflat/ast/LiteralNode.java: new method #memref.
* net/loveruby/cflat/ast/IntegerLiteralNode.java: implement it.
* net/loveruby/cflat/ast/StringLiteralNode.java: implement it.
* net/loveruby/cflat/ast/ConstantEntry.java: holds memref and address.
* net/loveruby/cflat/ast/AST.java: new method #allFunctions, to access undefined functions from code generator.
* net/loveruby/cflat/ast/ToplevelScope.java: ditto.


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4057 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2008-09-27 20:07:49 +00:00
parent ac9c042b57
commit 69862827dc
27 changed files with 617 additions and 197 deletions

View File

@ -1,3 +1,86 @@
Sun Sep 28 05:07:30 2008 Minero Aoki <aamine@loveruby.net>
* implement PIC generation.
* lib/Makefile: should generate PIC for libcbc.o.
* net/loveruby/cflat/compiler/Compiler.java: pass
CodeGeneratorOptions to CodeGenerator.
* net/loveruby/cflat/compiler/Options.java: new options -fpic,
-fPIC.
* net/loveruby/cflat/compiler/CodeGenerator.java: use position
independent address for global variables, common symbols,
defined/undefined functions and string constants.
* net/loveruby/cflat/compiler/CodeGeneratorOptions.java: new
class.
* net/loveruby/cflat/asm/ELFConstants.java: new interface to
define ELF-related constants.
* net/loveruby/cflat/asm/Assembler.java: new method #hidden.
* net/loveruby/cflat/asm/Assembler.java: new overload
#section(s,s,s,s,s).
* net/loveruby/cflat/asm/IndirectMemoryReference.java: offset may
not long, but Literal.
* net/loveruby/cflat/asm/Literal.java: new method #isZero.
* net/loveruby/cflat/asm/IntegerLiteral.java: ditto.
* net/loveruby/cflat/asm/LabelRef.java: ditto.
* net/loveruby/cflat/ast/ExprNode.java: new method
#shouldEvaluatedToAddres.
* net/loveruby/cflat/ast/VariableNode.java: override it.
* net/loveruby/cflat/ast/CastNode.java: override it.
* net/loveruby/cflat/ast/Entity.java: new method #cannotLoad, to
implement #shouldEvaluatedToAddress.
* net/loveruby/cflat/ast/Variable.java: override it.
* net/loveruby/cflat/ast/Function.java: override it.
* net/loveruby/cflat/ast/ExprNode.java: rename method: #AsmLiteral
-> #AsmValue because it now returns ImmediateValue instead of
Literal.
* net/loveruby/cflat/ast/CastNode.java: override it.
* net/loveruby/cflat/ast/LiteralNode.java: rename method also.
* net/loveruby/cflat/ast/IntegerLiteralNode.java: ditto.
* net/loveruby/cflat/ast/StringLiteralNode.java: ditto.
* net/loveruby/cflat/ast/Variable.java: holds memref and address
here, not in subclasses.
* net/loveruby/cflat/ast/DefinedVariable.java: ditto.
* net/loveruby/cflat/ast/UndefinedVariable.java: ditto.
* net/loveruby/cflat/ast/LiteralNode.java: new method #memref.
* net/loveruby/cflat/ast/IntegerLiteralNode.java: implement it.
* net/loveruby/cflat/ast/StringLiteralNode.java: implement it.
* net/loveruby/cflat/ast/ConstantEntry.java: holds memref and
address.
* net/loveruby/cflat/ast/AST.java: new method #allFunctions, to
access undefined functions from code generator.
* net/loveruby/cflat/ast/ToplevelScope.java: ditto.
Wed Sep 24 01:10:36 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/CodeGenerator.java: remove unused

View File

@ -1,5 +1,5 @@
CBC = ../bin/cbc
CBFLAGS = -O
CBFLAGS = -O -fPIC
TARGET = libcbc.a
OBJS = libcbc.o

View File

@ -119,6 +119,10 @@ public class Assembler {
directive("\t.section\t" + name);
}
public void _section(String name, String flags, String type, String group, String linkage) {
directive("\t.section\t" + name + "," + flags + "," + type + "," + group + "," + linkage);
}
public void _globl(String sym) {
directive(".globl " + sym);
}
@ -127,6 +131,10 @@ public class Assembler {
directive(".local " + sym);
}
public void _hidden(String sym) {
directive("\t.hidden\t" + sym);
}
public void _comm(String sym, long size, long alignment) {
directive("\t.comm\t" + sym + "," + size + "," + alignment);
}
@ -160,7 +168,7 @@ public class Assembler {
}
public void _long(Label sym) {
directive(".long\t" + sym.toString());
directive(".long\t" + sym);
}
public void _quad(long n) {
@ -168,7 +176,7 @@ public class Assembler {
}
public void _quad(Label sym) {
directive(".quad\t" + sym.toString());
directive(".quad\t" + sym);
}
public void _string(String str) {

View File

@ -0,0 +1,21 @@
package net.loveruby.cflat.asm;
public interface ELFConstants {
// Flags
static public final String SectionFlag_allocatable = "a";
static public final String SectionFlag_writable = "w";
static public final String SectionFlag_executable = "x";
static public final String SectionFlag_sectiongroup = "G";
static public final String SectionFlag_strings = "S";
static public final String SectionFlag_threadlocalstorage = "T";
// argument of "G" flag
static public final String Linkage_linkonce = "comdat";
// Types
static public final String SectionType_bits = "@progbits";
static public final String SectionType_nobits = "@nobits";
static public final String SectionType_note = "@note";
static public final String SymbolType_function = "@function";
}

View File

@ -1,23 +1,29 @@
package net.loveruby.cflat.asm;
public class IndirectMemoryReference extends MemoryReference {
protected long offset;
protected Literal offset;
protected Register base;
protected boolean fixed;
public IndirectMemoryReference(Register base) {
this.offset = 0;
this.offset = new IntegerLiteral(0);
this.base = base;
this.fixed = false;
}
public IndirectMemoryReference(long offset, Register base) {
this.offset = offset;
this.offset = new IntegerLiteral(offset);
this.base = base;
this.fixed = true;
}
public long offset() {
public IndirectMemoryReference(Label offset, Register base) {
this.offset = new LabelRef(offset);
this.base = base;
this.fixed = true;
}
public Literal offset() {
return offset;
}
@ -25,7 +31,7 @@ public class IndirectMemoryReference extends MemoryReference {
if (fixed) {
throw new Error("must not happen: fixed = true");
}
this.offset = realOffset;
this.offset = new IntegerLiteral(realOffset);
this.fixed = true;
}
@ -41,6 +47,7 @@ public class IndirectMemoryReference extends MemoryReference {
if (! fixed) {
throw new Error("must not happen: writing unfixed variable");
}
return (offset == 0 ? "" : "" + offset) + "(" + base.toSource() + ")";
return (offset.isZero() ? "" : offset.toSource())
+ "(" + base.toSource() + ")";
}
}

View File

@ -17,6 +17,10 @@ public class IntegerLiteral extends Literal {
return this.value;
}
public boolean isZero() {
return value == 0;
}
public IntegerLiteral integerLiteral() {
return this;
}

View File

@ -15,6 +15,10 @@ public class LabelRef extends Literal {
return label.name();
}
public boolean isZero() {
return false;
}
public void collectStatistics(AsmStatistics stats) {
stats.labelUsed(label);
}

View File

@ -3,4 +3,5 @@ package net.loveruby.cflat.asm;
abstract public class Literal {
abstract public String toSource();
abstract public void collectStatistics(AsmStatistics stats);
abstract public boolean isZero();
}

View File

@ -71,10 +71,21 @@ public class AST extends Node {
return declarations.defuns().iterator();
}
public Iterator allFunctions() {
List result = new ArrayList();
result.addAll(declarations.defuns());
result.addAll(declarations.funcdecls());
return result.iterator();
}
public ToplevelScope scope() {
return scope;
}
public Iterator allGlobalVariables() {
return scope.allGlobalVariables().iterator();
}
public Iterator globalVariables() {
return scope.globalVariables().iterator();
}

View File

@ -27,12 +27,16 @@ public class CastNode extends ExprNode {
return expr;
}
public boolean shouldEvaluatedToAddress() {
return expr.shouldEvaluatedToAddress();
}
public boolean isConstant() {
return expr.isConstant();
}
public Literal asmLiteral() {
return expr.asmLiteral();
public ImmediateValue asmValue() {
return expr.asmValue();
}
public boolean isEffectiveCast() {

View File

@ -1,17 +1,16 @@
package net.loveruby.cflat.ast;
import net.loveruby.cflat.asm.AsmOperand;
import net.loveruby.cflat.asm.Label;
import net.loveruby.cflat.asm.*;
public class ConstantEntry
{
public class ConstantEntry {
protected long id;
protected String value;
protected Label label;
protected MemoryReference memref;
protected ImmediateValue address;
public ConstantEntry(long i, String val) {
id = i;
value = val;
label = new Label(".LC" + id);
}
public long id() {
@ -22,7 +21,37 @@ public class ConstantEntry
return value;
}
public String symbol() {
return this.label.toString();
}
public void setLabel(Label label) {
this.label = label;
}
public Label label() {
return label;
if (this.label == null) {
throw new Error("must not happen: label == null");
}
return this.label;
}
public void setMemref(MemoryReference mem) {
this.memref = mem;
}
public MemoryReference memref() {
if (this.memref == null) {
throw new Error("must not happen: memref == null");
}
return this.memref;
}
public void setAddress(ImmediateValue imm) {
this.address = imm;
}
public ImmediateValue address() {
return this.address;
}
}

View File

@ -3,8 +3,8 @@ import net.loveruby.cflat.type.*;
import net.loveruby.cflat.asm.*;
public class DefinedVariable extends Variable {
protected long sequence;
protected ExprNode initializer;
protected MemoryReference memref;
public DefinedVariable(boolean priv, TypeNode type,
String name, ExprNode init) {
@ -17,6 +17,14 @@ public class DefinedVariable extends Variable {
return true;
}
public void setSequence(long seq) {
this.sequence = seq;
}
public String symbol() {
return (sequence < 0) ? name : (name + "." + sequence);
}
public boolean hasInitializer() {
return (initializer != null);
}
@ -33,21 +41,6 @@ public class DefinedVariable extends Variable {
this.initializer = expr;
}
public void setMemref(MemoryReference mem) {
this.memref = mem;
}
public MemoryReference memref() {
if (memref == null) {
throw new Error("unresolved variable address");
}
return memref;
}
public AsmOperand address() {
return null;
}
protected void _dump(Dumper d) {
d.printMember("name", name);
d.printMember("isPrivate", isPrivate);

View File

@ -19,6 +19,10 @@ abstract public class Entity extends Node {
return name;
}
public String symbol() {
return name();
}
abstract public boolean isDefined();
abstract public boolean isInitialized();
@ -52,6 +56,8 @@ abstract public class Entity extends Node {
return (nRefered > 0);
}
abstract public boolean cannotLoad();
abstract public MemoryReference memref();
abstract public AsmOperand address();

View File

@ -28,14 +28,6 @@ abstract public class ExprNode extends Node {
}
}
public boolean isConstant() {
return false;
}
public Literal asmLiteral() {
throw new Error("ExprNode#asmLiteral called");
}
public boolean isAssignable() {
return false;
}
@ -44,6 +36,18 @@ abstract public class ExprNode extends Node {
return false;
}
public boolean shouldEvaluatedToAddress() {
return false;
}
public boolean isConstant() {
return false;
}
public ImmediateValue asmValue() {
throw new Error("ExprNode#asmValue called");
}
public boolean isConstantAddress() {
return false;
}

View File

@ -4,6 +4,9 @@ import net.loveruby.cflat.asm.*;
import java.util.*;
abstract public class Function extends Entity {
protected String symbol;
protected AsmOperand address;
public Function(boolean priv, TypeNode t, String name) {
super(priv, t, name);
}
@ -25,16 +28,41 @@ abstract public class Function extends Entity {
return returnType().isVoid();
}
public boolean cannotLoad() {
return true;
}
public void setSymbol(String sym) {
if (this.symbol != null) {
throw new Error("must not happen: Function#symbol was set again");
}
this.symbol = sym;
}
public String symbol() {
if (this.symbol == null) {
throw new Error("must not happen: Function#symbol called but null");
}
return this.symbol;
}
public MemoryReference memref() {
return null;
}
public void setAddress(AsmOperand addr) {
this.address = addr;
}
public AsmOperand address() {
return new ImmediateValue(label());
if (address == null) {
throw new Error("must not happen: Function.address == null");
}
return this.address;
}
public Label label() {
// FIXME: should cache
return new Label(name);
return new Label(symbol());
}
}

View File

@ -1,7 +1,6 @@
package net.loveruby.cflat.ast;
import net.loveruby.cflat.type.*;
import net.loveruby.cflat.asm.Literal;
import net.loveruby.cflat.asm.IntegerLiteral;
import net.loveruby.cflat.asm.*;
public class IntegerLiteralNode extends LiteralNode {
protected long value;
@ -15,8 +14,12 @@ public class IntegerLiteralNode extends LiteralNode {
return value;
}
public Literal asmLiteral() {
return new IntegerLiteral(value);
public ImmediateValue asmValue() {
return new ImmediateValue(new IntegerLiteral(value));
}
public MemoryReference memref() {
throw new Error("must not happen: IntegerLiteralNode#memref");
}
protected void _dump(Dumper d) {

View File

@ -1,6 +1,6 @@
package net.loveruby.cflat.ast;
import net.loveruby.cflat.type.*;
import net.loveruby.cflat.asm.Literal;
import net.loveruby.cflat.asm.*;
abstract public class LiteralNode extends ExprNode {
protected Location location;
@ -28,5 +28,6 @@ abstract public class LiteralNode extends ExprNode {
return true;
}
abstract public Literal asmLiteral();
abstract public ImmediateValue asmValue();
abstract public MemoryReference memref();
}

View File

@ -5,6 +5,8 @@ import net.loveruby.cflat.asm.*;
public class StringLiteralNode extends LiteralNode {
protected String value;
protected ConstantEntry entry;
protected ImmediateValue asmValue;
protected MemoryReference memref;
public StringLiteralNode(Location loc, TypeRef ref, String value) {
super(loc, ref);
@ -24,8 +26,16 @@ public class StringLiteralNode extends LiteralNode {
return entry.label();
}
public Literal asmLiteral() {
return new LabelRef(label());
public MemoryReference memref() {
return entry.memref();
}
public AsmOperand address() {
return entry.address();
}
public ImmediateValue asmValue() {
return entry.address();
}
protected long id() {

View File

@ -51,6 +51,28 @@ public class ToplevelScope extends Scope {
return staticLocalVariables;
}
/** Returns a list of all global variables.
* "All global variable" means:
*
* * has global scope
* * defined or undefined
* * public or private
*/
public List allGlobalVariables() {
List result = new ArrayList();
List src = new ArrayList();
src.addAll(entities.values());
src.addAll(staticLocalVariables());
Iterator ents = src.iterator();
while (ents.hasNext()) {
Object ent = ents.next();
if (ent instanceof Variable) {
result.add(ent);
}
}
return result;
}
/** Returns the list of global variables.
* A global variable is a variable which has
* global scope and is initialized. */

View File

@ -11,22 +11,6 @@ public class UndefinedVariable extends Variable {
public boolean isPrivate() { return false; }
public boolean isInitialized() { return false; }
public String symbol() {
return name();
}
public void setMemref(MemoryReference mem) {
throw new Error("UndefinedVariable#Memref");
}
public MemoryReference memref() {
return new DirectMemoryReference(new Label(symbol()));
}
public AsmOperand address() {
return new ImmediateValue(new Label(symbol()));
}
protected void _dump(Dumper d) {
d.printMember("name", name);
d.printMember("isPrivate", isPrivate());

View File

@ -3,20 +3,38 @@ import net.loveruby.cflat.type.*;
import net.loveruby.cflat.asm.*;
abstract public class Variable extends Entity {
protected long sequence;
protected MemoryReference memref;
protected MemoryReference address;
public Variable(boolean priv, TypeNode type, String name) {
super(priv, type, name);
sequence = -1;
}
public void setSequence(long seq) {
this.sequence = seq;
public boolean cannotLoad() {
return type().isAllocatedArray();
}
public String symbol() {
return (sequence < 0) ? name : (name + "." + sequence);
public void setMemref(MemoryReference mem) {
this.memref = mem;
}
abstract public void setMemref(MemoryReference addr);
public MemoryReference memref() {
checkAddress();
return memref;
}
public void setAddress(MemoryReference mem) {
this.address = mem;
}
public AsmOperand address() {
checkAddress();
return address;
}
protected void checkAddress() {
if (memref == null && address == null) {
throw new Error("address did not resolved: " + name);
}
}
}

View File

@ -48,6 +48,10 @@ public class VariableNode extends ExprNode {
return entity().isParameter();
}
public boolean shouldEvaluatedToAddress() {
return entity().cannotLoad();
}
public boolean isConstantAddress() {
return true;
}

View File

@ -4,22 +4,20 @@ import net.loveruby.cflat.type.*;
import net.loveruby.cflat.asm.*;
import java.util.*;
public class CodeGenerator extends Visitor implements ASTLHSVisitor {
public class CodeGenerator
extends Visitor implements ASTLHSVisitor, ELFConstants {
// #@@range/ctor{
protected AsmOptimizer optimizer;
protected CodeGeneratorOptions options;
protected ErrorHandler errorHandler;
protected boolean verboseAsm;
protected LinkedList asStack;
protected Assembler as;
protected TypeTable typeTable;
protected DefinedFunction currentFunction;
public CodeGenerator(AsmOptimizer optimizer,
ErrorHandler errorHandler,
boolean verboseAsm) {
this.optimizer = optimizer;
public CodeGenerator(CodeGeneratorOptions options,
ErrorHandler errorHandler) {
this.options = options;
this.errorHandler = errorHandler;
this.verboseAsm = verboseAsm;
this.asStack = new LinkedList();
}
// #@@}
@ -29,8 +27,9 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
public String generate(AST ast) {
this.typeTable = ast.typeTable();
pushAssembler();
allocateGlobalVariables(ast.globalVariables());
allocateCommonSymbols(ast.commonSymbols());
resolveConstants(ast.constantTable());
resolveGlobalVariables(ast.allGlobalVariables());
resolveFunctions(ast.allFunctions());
compileAST(ast);
return popAssembler().toSource();
}
@ -66,48 +65,100 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
}
// .bss
compileCommonSymbols(ast.commonSymbols());
// others
if (options.isPICRequired()) {
PICThunk(GOTBaseReg());
}
}
// #@@}
protected void resolveConstants(ConstantTable table) {
Iterator ents = table.entries();
while (ents.hasNext()) {
ConstantEntry ent = (ConstantEntry)ents.next();
ent.setLabel(new Label(".LC" + ent.id()));
if (options.isPICRequired()) {
Label offset = new Label(localGOTSymbol(ent.symbol()));
ent.setMemref(mem(offset, GOTBaseReg()));
}
else {
ent.setMemref(mem(ent.label()));
ent.setAddress(imm(ent.label()));
}
}
}
/**
* Sets memory reference for...
* * public global variables
* * private global variables
* * static local variables
*/
// #@@range/allocateGlobalVariable
protected void allocateGlobalVariables(Iterator vars) {
while (vars.hasNext()) {
Variable var = (Variable)vars.next();
var.setMemref(globalVariableAddress(var.symbol()));
}
}
// #@@}
/**
* Sets address for...
* * public common symbols
* * private common symbols
* * static local variables
*/
// #@@range/allocateCommonSymbols
protected void allocateCommonSymbols(Iterator comms) {
while (comms.hasNext()) {
Variable var = (Variable)comms.next();
var.setMemref(commonSymbolAddress(var.symbol()));
// #@@range/resolveGlobalVariables
protected void resolveGlobalVariables(Iterator vars) {
while (vars.hasNext()) {
Variable var = (Variable)vars.next();
resolveGlobalVariable(var);
}
}
// #@@}
/** Linux/IA-32 dependent */
// FIXME: PIC
protected MemoryReference globalVariableAddress(String sym) {
return new DirectMemoryReference(new Label(csymbol(sym)));
protected void resolveGlobalVariable(Variable var) {
String sym = var.symbol();
MemoryReference mem;
if (options.isPICRequired()) {
if (var.isPrivate()) {
mem = mem(new Label(localGOTSymbol(sym)), GOTBaseReg());
var.setMemref(mem);
}
else {
mem = mem(new Label(globalGOTSymbol(sym)), GOTBaseReg());
var.setAddress(mem);
}
}
else {
mem = mem(new Label(csymbol(sym)));
var.setMemref(mem);
}
}
/** Linux/IA-32 dependent */
// FIXME: PIC
protected MemoryReference commonSymbolAddress(String sym) {
return new DirectMemoryReference(new Label(csymbol(sym)));
protected void resolveFunctions(Iterator funcs) {
while (funcs.hasNext()) {
Function func = (Function)funcs.next();
func.setSymbol(functionSymbol(func));
func.setAddress(functionAddress(func));
}
}
protected String functionSymbol(Function func) {
if (func.isDefined()) {
return csymbol(func.name());
}
else {
if (options.isPICRequired()) {
return PLTSymbol(tmpsymbol(func.name()));
}
else {
return tmpsymbol(func.name());
}
}
}
protected AsmOperand functionAddress(Function func) {
if (options.isPICRequired()) {
String name = func.name();
if (func.isPrivate()) {
return mem(new Label(localGOTSymbol(name)), GOTBaseReg());
}
else {
return mem(new Label(globalGOTSymbol(name)), GOTBaseReg());
}
}
else {
return imm(func.label());
}
}
/** Generates static variable entries */
@ -188,6 +239,84 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
}
// #@@}
// #@@range/tmpsymbol{
// platform dependent
protected String tmpsymbol(String sym) {
return sym;
}
// #@@}
// #@@range/csymbol{
// platform dependent
protected String csymbol(String sym) {
return sym;
}
// #@@}
//
// PIC related constants and codes
//
static protected final String GOTName = "_GLOBAL_OFFSET_TABLE_";
protected void loadGOTBaseAddress(Register reg) {
call(PICThunkName(reg));
add(imm(new Label(GOTName)), reg);
}
protected String PICThunkName(Register reg) {
return "__i686.get_pc_thunk." + reg.baseName();
}
protected Register GOTBaseReg() {
return reg("bx");
}
protected String globalGOTSymbol(String base) {
return base + "@GOT";
}
protected String localGOTSymbol(String base) {
return base + "@GOTOFF";
}
protected String PLTSymbol(String base) {
return base + "@PLT";
}
static protected final String
PICThunkSectionFlags = SectionFlag_allocatable
+ SectionFlag_executable
+ SectionFlag_sectiongroup;
protected void PICThunk(Register reg) {
// ELF section declaration; format:
//
// .section NAME, FLAGS, TYPE, flag_arguments
//
// FLAGS, TYPE, flag_arguments are optional.
// For "M" flag (a member of a section group),
// format is:
//
// .section NAME, "...M", TYPE, section_group_name, linkage
//
_section(".text" + "." + PICThunkName(reg),
"\"" + PICThunkSectionFlags + "\"",
SectionType_bits, // This section contains data
PICThunkName(reg), // The name of section group
Linkage_linkonce); // Only 1 copy should be generated
_globl(PICThunkName(reg));
_hidden(PICThunkName(reg));
_type(PICThunkName(reg), SymbolType_function);
label(PICThunkName(reg));
mov(mem(sp()), reg); // fetch saved EIP to the GOT base register
ret();
}
//
// Compile Function
//
/** Compiles all functions and generates .text section. */
// #@@range/compileFunctions{
protected void compileFunctions(Iterator funcs) {
@ -222,6 +351,9 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
long lvarBytes = allocateLocalVariables(func.body().scope(),
saveRegs.size());
prologue(func, saveRegs, lvarBytes);
if (options.isPICRequired() && stats.doesRegisterUsed(GOTBaseReg())) {
loadGOTBaseAddress(GOTBaseReg());
}
as.addAll(bodyAsms);
epilogue(func, saveRegs, lvarBytes);
}
@ -232,7 +364,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
compile(func.body());
label(epilogueLabel(func));
currentFunction = null;
return optimizer.optimize(popAssembler().assemblies());
return options.optimizer().optimize(popAssembler().assemblies());
}
protected List reduceLabels(List assemblies, AsmStatistics stats) {
@ -252,32 +384,18 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
// #@@range/compile{
protected void compile(Node n) {
if (verboseAsm) {
if (options.isVerboseAsm()) {
comment(n.getClass().getSimpleName() + " {");
as.indentComment();
}
n.accept(this);
if (verboseAsm) {
if (options.isVerboseAsm()) {
as.unindentComment();
comment("}");
}
}
// #@@}
// #@@range/tmpsymbol{
// platform dependent
protected String tmpsymbol(String sym) {
return sym;
}
// #@@}
// #@@range/csymbol{
// platform dependent
protected String csymbol(String sym) {
return sym;
}
// #@@}
protected List usedCalleeSavedRegisters(AsmStatistics stats) {
List result = new ArrayList();
Iterator regs = calleeSavedRegisters().iterator();
@ -348,7 +466,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
mov(sp(), bp());
saveRegisters(saveRegs);
extendStack(lvarBytes);
if (verboseAsm) {
if (options.isVerboseAsm()) {
Iterator vars = func.localVariables();
while (vars.hasNext()) {
DefinedVariable var = (DefinedVariable)vars.next();
@ -481,34 +599,32 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
}
}
/** cdecl call
*
* * all arguments are on stack
* * rollback stack by caller
/**
* Implements cdecl function call:
* * All arguments are on stack.
* * Rewind stack by caller.
*/
public void visit(FuncallNode node) {
ListIterator it = node.finalArg();
while (it.hasPrevious()) {
ExprNode arg = (ExprNode)it.previous();
// compile function arguments from right to left.
ListIterator args = node.finalArg();
while (args.hasPrevious()) {
ExprNode arg = (ExprNode)args.previous();
compile(arg);
push(reg("ax"));
}
// call
if (node.isStaticCall()) {
if (node.function().isDefined()) {
call(csymbol(node.function().name()));
}
else {
call(tmpsymbol(node.function().name()));
}
// call via function name
call(node.function().symbol());
}
else { // function call via pointer
else {
// call via pointer
compile(node.expr());
callAbsolute(reg("ax"));
}
if (node.numArgs() > 0) {
// >4 bytes arguments are not supported.
shrinkStack(node.numArgs() * stackWordSize);
}
// rewind stack
// >4 bytes arguments are not supported.
shrinkStack(node.numArgs() * stackWordSize);
}
public void visit(ReturnNode node) {
@ -538,7 +654,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
}
protected void compileStmt(Node node) {
if (verboseAsm) {
if (options.isVerboseAsm()) {
comment(node.location().numberedLine());
}
compile(node);
@ -683,7 +799,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
AsmOperand right = null;
if (!doesRequireRegister(node.operator()) && node.right().isConstant()){
compile(node.left());
right = imm(node.right().asmLiteral());
right = node.right().asmValue();
}
else if (node.right().isConstantAddress()) {
compile(node.left());
@ -927,7 +1043,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
compileLHS(node.lhs());
mov(reg("ax"), reg("cx"));
load(node.type(), mem(reg("cx")), reg("ax"));
AsmOperand rhs = imm(node.rhs().asmLiteral());
AsmOperand rhs = node.rhs().asmValue();
compileBinaryOp(node.operator(), node.type(), rhs);
save(node.type(), reg("ax"), mem(reg("cx")));
}
@ -981,12 +1097,12 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
}
protected void compileLHS(Node node) {
if (verboseAsm) {
if (options.isVerboseAsm()) {
comment("compileLHS: " + node.getClass().getSimpleName() + " {");
as.indentComment();
}
node.acceptLHS(this);
if (verboseAsm) {
if (options.isVerboseAsm()) {
as.unindentComment();
comment("compileLHS: }");
}
@ -1044,7 +1160,15 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
* before calling this method.
*/
protected void loadConstant(ExprNode node, Register reg) {
mov(imm(node.asmLiteral()), reg);
if (node.asmValue() != null) {
mov(node.asmValue(), reg);
}
else if (node.memref() != null) {
lea(node.memref(), reg);
}
else {
throw new Error("must not happen: constant has no asm value");
}
}
/**
@ -1052,13 +1176,14 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
* by #isConstantAddress before calling this method.
*/
protected void loadVariable(ExprNode node, Register dest) {
if (node.type().isAllocatedArray()) {
// int[4] a; a implies &a
if (node.shouldEvaluatedToAddress()) {
// "int[4] a; a" implies &a
// "x = puts" implies &puts
loadVariableAddress(node, dest);
}
else if (node.memref() == null) {
// "puts" equivalent to "&ptr"
mov(node.address(), dest);
load(node.type(), mem(dest), dest);
}
else {
// regular variable
@ -1097,6 +1222,10 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
return new Register(name);
}
protected DirectMemoryReference mem(Label label) {
return new DirectMemoryReference(label);
}
protected IndirectMemoryReference mem(Register reg) {
return new IndirectMemoryReference(0, reg);
}
@ -1105,6 +1234,10 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
return new IndirectMemoryReference(offset, reg);
}
protected IndirectMemoryReference mem(Label offset, Register reg) {
return new IndirectMemoryReference(offset, reg);
}
protected ImmediateValue imm(long n) {
return new ImmediateValue(n);
}
@ -1148,8 +1281,10 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
public void _text() { as._text(); }
public void _data() { as._data(); }
public void _section(String name) { as._section(name); }
public void _section(String name, String flags, String type, String group, String linkage) { as._section(name, flags, type, group, linkage); }
public void _globl(String sym) { as._globl(sym); }
public void _local(String sym) { as._local(sym); }
public void _hidden(String sym) { as._hidden(sym); }
public void _comm(String sym, long sz, long a) { as._comm(sym, sz, a); }
public void _align(long n) { as._align(n); }
public void _type(String sym, String type) { as._type(sym, type); }

View File

@ -0,0 +1,48 @@
package net.loveruby.cflat.compiler;
import net.loveruby.cflat.asm.*;
import java.util.*;
class CodeGeneratorOptions {
protected int optimizeLevel;
protected boolean generatePIC;
protected boolean verboseAsm;
public CodeGeneratorOptions() {
optimizeLevel = 0;
generatePIC = false;
verboseAsm = false;
}
public void setOptimizationLevel(int level) {
this.optimizeLevel = level;
}
public AsmOptimizer optimizer() {
if (optimizeLevel > 0) {
return PeepholeOptimizer.defaultSet();
}
else {
return new NullOptimizer();
}
}
class NullOptimizer implements AsmOptimizer {
public List optimize(List assemblies) { return assemblies; }
}
public void generateVerboseAsm() {
this.verboseAsm = true;
}
public boolean isVerboseAsm() {
return verboseAsm;
}
public void generatePIC() {
this.generatePIC = true;
}
public boolean isPICRequired() {
return generatePIC;
}
}

View File

@ -185,9 +185,7 @@ public class Compiler {
}
protected String generateAssembly(AST ast, Options opts) {
CodeGenerator gen = new CodeGenerator(opts.optimizer(),
errorHandler,
opts.isVerboseAsm());
CodeGenerator gen = new CodeGenerator(opts.genOptions(), errorHandler);
return gen.generate(ast);
}

View File

@ -13,8 +13,7 @@ class Options {
protected String outputFileName;
protected boolean verbose;
protected boolean debugParser;
protected int optimizeLevel = 0;
protected boolean verboseAsm = false;
protected CodeGeneratorOptions genOptions;
protected List asOptions; // List<String>
protected List ldArgs; // List<LdArg>
protected boolean noStartFiles = false;
@ -23,6 +22,7 @@ class Options {
public Options(TypeTable typeTable, LibraryLoader loader) {
this.typeTable = typeTable;
this.loader = loader;
this.genOptions = new CodeGeneratorOptions();
this.asOptions = new ArrayList();
this.ldArgs = new ArrayList();
}
@ -114,21 +114,8 @@ class Options {
return this.debugParser;
}
public AsmOptimizer optimizer() {
if (optimizeLevel == 0) {
return new NullAsmOptimizer();
}
else {
return PeepholeOptimizer.defaultSet();
}
}
class NullAsmOptimizer implements AsmOptimizer {
public List optimize(List assemblies) { return assemblies; }
}
public boolean isVerboseAsm() {
return verboseAsm;
public CodeGeneratorOptions genOptions() {
return genOptions;
}
// List<String>
@ -189,23 +176,24 @@ class Options {
else if (arg.startsWith("-o")) {
outputFileName = getOptArg(arg, args);
}
// FIXME: PIC
//else if (arg.equals("-fpic"))
//else if (arg.equals("-fPIC"))
// -shared ??
else if (arg.equals("-fpic")) {
genOptions.generatePIC();
}
else if (arg.equals("-fPIC")) {
genOptions.generatePIC();
}
// FIXME: PIE
//else if (arg.equals("-fpie"))
//else if (arg.equals("-fPIE"))
//else if (arg.equals("-pie"))
else if (arg.startsWith("-O")) {
String type = arg.substring(2);
if (! type.matches("^([0123s]|)$")) {
parseError("unknown optimization switch: " + arg);
}
optimizeLevel = type.equals("0") ? 0 : 1;
genOptions.setOptimizationLevel(type.equals("0") ? 0 : 1);
}
else if (arg.equals("--verbose-asm")) {
verboseAsm = true;
genOptions.generateVerboseAsm();
}
else if (arg.startsWith("-Wa,")) {
asOptions.addAll(parseCommaSeparatedOptions(arg));
@ -217,8 +205,10 @@ class Options {
ldArgs.add(new LdOption(arg));
}
else if (arg.equals("-shared")) {
// FIXME: ?? any more work is required??
ldArgs.add(new LdOption(arg));
}
//else if (arg.equals("-pie"))
else if (arg.startsWith("-L")) {
ldArgs.add(new LdOption("-L" + getOptArg(arg, args)));
}
@ -329,30 +319,30 @@ class Options {
public void printUsage(PrintStream out) {
out.println("Usage: cbc [options] file...");
out.println("Generic Options:");
out.println(" --check-syntax Checks syntax.");
out.println(" --dump-tokens Parses source file and dumps tokens.");
out.println(" --dump-ast Parses source file and dumps AST.");
out.println(" --dump-semantic Checks semantics and dumps AST.");
out.println("Global Options:");
out.println(" --check-syntax Checks syntax and quit.");
out.println(" --dump-tokens Dumps tokens and quit.");
out.println(" --dump-ast Dumps AST and quit.");
out.println(" --dump-semantic Dumps AST after semantic check and quit.");
// --dump-reference is hidden option
out.println(" -S Generates an assembly source.");
out.println(" --dump-asm Dumps an assembly source.");
out.println(" -c Generates an object file.");
out.println(" -S Generates an assembly source and quit.");
out.println(" --dump-asm Prints an assembly source and quit.");
out.println(" -c Generates an object file and quit.");
out.println(" -o PATH Places output in file PATH.");
out.println(" -v Verbose mode.");
out.println(" --version Shows compiler version.");
out.println(" -v Turn on verbose mode.");
out.println(" --version Shows compiler version and quit.");
out.println(" --help Prints this message and quit.");
out.println("");
out.println("Parser Options:");
out.println(" -I PATH Adds PATH as import file directory.");
out.println(" --debug-parser Dumps parsing process.");
out.println("");
out.println("Compiler Options:");
out.println(" -I PATH Adds PATH as import file directory.");
out.println("Code Generator Options:");
out.println(" -O Enables optimization.");
out.println(" -O1, -O2, -O3 Equivalent to -O.");
out.println(" -Os Equivalent to -O.");
out.println(" -O0 Disables optimization (default).");
//out.println(" -fPIC Generates PIC assembly.");
out.println(" -fPIC Generates PIC assembly.");
//out.println(" -fPIE Generates PIE assembly.");
out.println(" --verbose-asm Generate assembly with verbose comments.");
out.println("");
@ -363,8 +353,8 @@ class Options {
out.println("Linker Options:");
out.println(" -l LIB Links the library LIB.");
out.println(" -L PATH Adds PATH as library directory.");
//out.println(" -shared Linkes with shared library (default).");
//out.println(" -static Linkes with static library.");
out.println(" -shared Generates shared library rather than executable.");
out.println(" -static Linkes only with static libraries.");
//out.println(" -pie Generates PIE.");
out.println(" -nostartfiles Do not link startup files.");
out.println(" -nodefaultlibs Do not link default libraries.");

View File

@ -322,6 +322,10 @@ assert_out() {
assert_compile_success "$1.cb" &&
assert_stdout "$msg" "$@" &&
assert_compile_success -O "$1.cb" &&
assert_stdout "$msg" "$@" &&
assert_compile_success -fPIC "$1.cb" &&
assert_stdout "$msg" "$@" &&
assert_compile_success -O -fPIC "$1.cb" &&
assert_stdout "$msg" "$@"
}