mirror of https://github.com/aamine/cbc
* 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:
parent
ac9c042b57
commit
69862827dc
83
ChangeLog
83
ChangeLog
|
@ -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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
CBC = ../bin/cbc
|
||||
CBFLAGS = -O
|
||||
CBFLAGS = -O -fPIC
|
||||
TARGET = libcbc.a
|
||||
OBJS = libcbc.o
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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";
|
||||
}
|
|
@ -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() + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@ public class IntegerLiteral extends Literal {
|
|||
return this.value;
|
||||
}
|
||||
|
||||
public boolean isZero() {
|
||||
return value == 0;
|
||||
}
|
||||
|
||||
public IntegerLiteral integerLiteral() {
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,10 @@ public class VariableNode extends ExprNode {
|
|||
return entity().isParameter();
|
||||
}
|
||||
|
||||
public boolean shouldEvaluatedToAddress() {
|
||||
return entity().cannotLoad();
|
||||
}
|
||||
|
||||
public boolean isConstantAddress() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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" "$@"
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue