diff --git a/gen/argument_info.go b/gen/argument_info.go index d4e572c..97d4ee5 100644 --- a/gen/argument_info.go +++ b/gen/argument_info.go @@ -9,7 +9,7 @@ type ArgumentInfo interface { GetType() *ReferencedTypeInfo // The location where the argument appears in the source code. - Declaration() core.UnmanagedSourceView + Declaration() *core.UnmanagedSourceView // Returns the argument string, as it should appear in the code code. String() string diff --git a/gen/immediate_info.go b/gen/immediate_info.go index 71c4357..8c89ef7 100644 --- a/gen/immediate_info.go +++ b/gen/immediate_info.go @@ -17,8 +17,8 @@ func (i *ImmediateInfo) GetType() *ReferencedTypeInfo { return &i.Type } -func (i *ImmediateInfo) Declaration() core.UnmanagedSourceView { - return i.declaration +func (i *ImmediateInfo) Declaration() *core.UnmanagedSourceView { + return &i.declaration } func (i *ImmediateInfo) String() string { diff --git a/gen/instruction_generator.go b/gen/instruction_generator.go index 10d6034..25e1753 100644 --- a/gen/instruction_generator.go +++ b/gen/instruction_generator.go @@ -8,7 +8,7 @@ import ( type InstructionGenerator struct { ArgumentGenerator InstructionContextGenerator[parse.ArgumentNode, ArgumentInfo] - TargetGenerator InstructionContextGenerator[parse.TargetNode, registerPartialInfo] + TargetGenerator InstructionContextGenerator[parse.TargetNode, *RegisterInfo] } func NewInstructionGenerator() FunctionContextGenerator[ @@ -45,23 +45,44 @@ func (g *InstructionGenerator) generateArguments( return arguments, results } -func (g *InstructionGenerator) generatePartialTargetsInfo( +func (g *InstructionGenerator) generateTargets( ctx *InstructionGenerationContext, node parse.InstructionNode, -) ([]registerPartialInfo, core.ResultList) { - targets := make([]registerPartialInfo, len(node.Targets)) +) ([]*RegisterArgumentInfo, core.ResultList) { + targets := make([]*RegisterArgumentInfo, len(node.Targets)) results := core.ResultList{} - // Different targets should not effect one another. - // Thus, we just collect all of the errors along the way, and return - // them in one chunk. for i, target := range node.Targets { - typeInfo, curResults := g.TargetGenerator.Generate(ctx, target) + v := target.View() + registerInfo, curResults := g.TargetGenerator.Generate(ctx, target) results.Extend(&curResults) - targets[i] = typeInfo + + if registerInfo == nil { + // TODO: improve error message + results.Append(core.Result{ + { + Type: core.ErrorResult, + Message: "Undefined or untyped register", + Location: &v, + }, + { + Type: core.HintResult, + Message: "A register must be defined with an explicit type at least once", + }, + }) + } + + targets[i] = &RegisterArgumentInfo{ + Register: registerInfo, + declaration: &v, + } } - return targets, results + if !results.IsEmpty() { + return nil, results + } + + return targets, core.ResultList{} } func (g *InstructionGenerator) generateLabels( @@ -87,115 +108,6 @@ func (g *InstructionGenerator) generateLabels( return labels, core.ResultList{} } -func partialTargetsToTypes(targets []registerPartialInfo) []*ReferencedTypeInfo { - types := make([]*ReferencedTypeInfo, len(targets)) - for i, target := range targets { - types[i] = target.Type - } - return types -} - -func argumentsToTypes(arguments []ArgumentInfo) []*ReferencedTypeInfo { - types := make([]*ReferencedTypeInfo, len(arguments)) - for i, arg := range arguments { - types[i] = arg.GetType() - } - return types -} - -func (g *InstructionGenerator) getTargetRegister( - ctx *InstructionGenerationContext, - node parse.TargetNode, - targetType ReferencedTypeInfo, -) (*RegisterInfo, core.ResultList) { - registerName := nodeToSourceString(ctx.FileGenerationContext, node.Register) - registerInfo := ctx.Registers.GetRegister(registerName) - nodeView := node.View() - - if registerInfo == nil { - // register is defined here; we should create the register and define - // it's type. - newRegisterInfo := &RegisterInfo{ - Name: registerName, - Type: targetType, - Declaration: nodeView, - } - - return newRegisterInfo, ctx.Registers.NewRegister(newRegisterInfo) - } - - // register is already defined - if !registerInfo.Type.Equal(targetType) { - // notest: sanity check only - return nil, list.FromSingle(core.Result{{ - Type: core.InternalErrorResult, - Message: "Internal register type mismatch", - Location: &nodeView, - }}) - } - - return registerInfo, core.ResultList{} -} - -// Registers can be defined by being a target of an instruction. -// After we have determined 100% of the instruction targets types (either -// if they were explicitly declared or not), we call this function with the -// target types, and here we iterate over all target types and define missing -// registers. -// -// This also returns the full list of register targets for the provided -// instruction. -func (g *InstructionGenerator) defineAndGetTargetRegisters( - ctx *InstructionGenerationContext, - node parse.InstructionNode, - targetTypes []ReferencedTypeInfo, -) ([]*RegisterArgumentInfo, core.ResultList) { - if len(node.Targets) != len(targetTypes) { - // notest: sanity check: ensure lengths match. - v := node.View() - return nil, list.FromSingle(core.Result{{ - Type: core.InternalErrorResult, - Message: "Targets length mismatch", - Location: &v, - }}) - } - - registers := make([]*RegisterArgumentInfo, len(node.Targets)) - results := core.ResultList{} - for i, target := range node.Targets { - // register errors should not effect one another, so we collect them. - registerInfo, curResults := g.getTargetRegister( - ctx, - target, - targetTypes[i], - ) - - if !results.IsEmpty() { - results.Extend(&curResults) - } - - if registerInfo == nil { - // notest: sanity check, should not happen. - v := target.View() - results.Append(core.Result{{ - Type: core.InternalErrorResult, - Message: "Unexpected nil register", - Location: &v, - }}) - } - - registerArgument := &RegisterArgumentInfo{ - Register: registerInfo, - declaration: node.View(), - } - - registerInfo.AddDefinition(ctx.InstructionInfo) - registers[i] = registerArgument - } - - return registers, results -} - // Convert an instruction parsed node into an instruction that is in the // instruction set. // If new registers are defined in the instruction (by assigning values to @@ -209,8 +121,6 @@ func (g *InstructionGenerator) Generate( // and processing the targets and arguments. We accumulate the results, // since those processes do not effect each other. - // TODO: tidy this mess. - v := node.View() instCtx := InstructionGenerationContext{ FunctionGenerationContext: ctx, @@ -223,7 +133,7 @@ func (g *InstructionGenerator) Generate( arguments, curResults := g.generateArguments(&instCtx, node) results.Extend(&curResults) - partialTargets, curResults := g.generatePartialTargetsInfo(&instCtx, node) + targets, curResults := g.generateTargets(&instCtx, node) results.Extend(&curResults) labels, curResults := g.generateLabels(&instCtx, node) @@ -235,24 +145,8 @@ func (g *InstructionGenerator) Generate( } instCtx.InstructionInfo.Arguments = arguments - instCtx.InstructionInfo.Labels = labels - - explicitTargetTypes := partialTargetsToTypes(partialTargets) - argumentTypes := argumentsToTypes(arguments) - targetTypes, results := instDef.InferTargetTypes(ctx, explicitTargetTypes, argumentTypes) - // TODO: validate that the returned target types matches expected constraints. - - if !results.IsEmpty() { - return nil, results - } - - targets, results := g.defineAndGetTargetRegisters(&instCtx, node, targetTypes) - - if !results.IsEmpty() { - return nil, results - } - instCtx.InstructionInfo.Targets = targets + instCtx.InstructionInfo.Labels = labels instruction, results := instDef.BuildInstruction(instCtx.InstructionInfo) if !results.IsEmpty() { diff --git a/gen/label_argument.go b/gen/label_argument.go index 3871beb..159bc40 100644 --- a/gen/label_argument.go +++ b/gen/label_argument.go @@ -11,15 +11,15 @@ import ( type LabelArgumentInfo struct { Label *LabelInfo - // TODO: make this not required. - declaration core.UnmanagedSourceView + declaration *core.UnmanagedSourceView } func NewLabelArgumentInfo( label *LabelInfo, ) *LabelArgumentInfo { return &LabelArgumentInfo{ - Label: label, + Label: label, + declaration: nil, } } @@ -27,7 +27,7 @@ func (i *LabelArgumentInfo) GetType() *ReferencedTypeInfo { return nil // Label argument does not have a type } -func (i *LabelArgumentInfo) Declaration() core.UnmanagedSourceView { +func (i *LabelArgumentInfo) Declaration() *core.UnmanagedSourceView { return i.declaration } @@ -63,9 +63,10 @@ func (g *LabelArgumentGenerator) Generate( }) } + v := node.View() argument := &LabelArgumentInfo{ Label: labelInfo, - declaration: node.View(), + declaration: &v, } return argument, core.ResultList{} diff --git a/gen/regisrer_partial_info.go b/gen/regisrer_partial_info.go deleted file mode 100644 index c0ba63b..0000000 --- a/gen/regisrer_partial_info.go +++ /dev/null @@ -1,15 +0,0 @@ -package gen - -import "alon.kr/x/usm/core" - -// This represents partial register information, possibly without an associated -// type (yet). This is used internally before the compiler has finally determined -// the type of the register, if the type is implicit. -type registerPartialInfo struct { - Name string - - // Possibly nil, if type is implicitly defined. - Type *ReferencedTypeInfo - - Declaration core.UnmanagedSourceView -} diff --git a/gen/register_argument.go b/gen/register_argument.go index 4ec84cd..39b8a87 100644 --- a/gen/register_argument.go +++ b/gen/register_argument.go @@ -10,10 +10,7 @@ import ( type RegisterArgumentInfo struct { Register *RegisterInfo - // TODO: make this not required, for generated arguments, for example after - // SSA construction (phi register arguments which do not appear in the - // source code). - declaration core.UnmanagedSourceView + declaration *core.UnmanagedSourceView } func NewRegisterArgument(register *RegisterInfo) RegisterArgumentInfo { @@ -30,7 +27,7 @@ func (i *RegisterArgumentInfo) GetType() *ReferencedTypeInfo { return &i.Register.Type } -func (i *RegisterArgumentInfo) Declaration() core.UnmanagedSourceView { +func (i *RegisterArgumentInfo) Declaration() *core.UnmanagedSourceView { return i.declaration } @@ -64,9 +61,10 @@ func (g *RegisterArgumentGenerator) Generate( return nil, results } + v := node.View() argument := RegisterArgumentInfo{ Register: register, - declaration: node.View(), + declaration: &v, } register.AddUsage(ctx.InstructionInfo) diff --git a/gen/register_info.go b/gen/register_info.go index 4e09f44..1095b76 100644 --- a/gen/register_info.go +++ b/gen/register_info.go @@ -51,11 +51,3 @@ func (i *RegisterInfo) AddDefinition(info *InstructionInfo) { func (i *RegisterInfo) AddUsage(info *InstructionInfo) { i.Usages = append(i.Usages, info) } - -func (i *RegisterInfo) toPartialRegisterInfo() registerPartialInfo { - return registerPartialInfo{ - Name: i.Name, - Type: &i.Type, - Declaration: i.Declaration, - } -} diff --git a/usm64/core/emulation.go b/usm64/core/emulation.go index a3843e8..7b0fe99 100644 --- a/usm64/core/emulation.go +++ b/usm64/core/emulation.go @@ -47,7 +47,7 @@ func (ctx *EmulationContext) ArgumentToValue( return 0, list.FromSingle(core.Result{{ Type: core.InternalErrorResult, Message: "Undefined register", - Location: &v, + Location: v, }}) } @@ -59,7 +59,7 @@ func (ctx *EmulationContext) ArgumentToValue( return 0, list.FromSingle(core.Result{{ Type: core.ErrorResult, Message: "Immediate overflows 64 bits", - Location: &v, + Location: v, }}) } @@ -70,7 +70,7 @@ func (ctx *EmulationContext) ArgumentToValue( return 0, list.FromSingle(core.Result{{ Type: core.ErrorResult, Message: "Expected valued argument", - Location: &v, + Location: v, }}) default: @@ -78,7 +78,7 @@ func (ctx *EmulationContext) ArgumentToValue( return 0, list.FromSingle(core.Result{{ Type: core.InternalErrorResult, Message: "Unexpected argument type", - Location: &v, + Location: v, }}) } } diff --git a/usm64/core/label.go b/usm64/core/label.go index a77aa49..80e25f7 100644 --- a/usm64/core/label.go +++ b/usm64/core/label.go @@ -8,13 +8,12 @@ import ( type Label struct { Name string InstructionIndex uint64 - declaration core.UnmanagedSourceView + declaration *core.UnmanagedSourceView } func NewLabel(arg gen.LabelArgumentInfo) (Label, core.ResultList) { return Label{ - Name: arg.Label.Name, - + Name: arg.Label.Name, declaration: arg.Declaration(), }, core.ResultList{} } @@ -23,6 +22,6 @@ func (l Label) String(*EmulationContext) string { return l.Name } -func (l Label) Declaration() core.UnmanagedSourceView { +func (l Label) Declaration() *core.UnmanagedSourceView { return l.declaration } diff --git a/usm64/core/register.go b/usm64/core/register.go index d86b62a..6bb4a93 100644 --- a/usm64/core/register.go +++ b/usm64/core/register.go @@ -9,7 +9,7 @@ import ( type Register struct { Name string - declaration core.UnmanagedSourceView + declaration *core.UnmanagedSourceView } func NewRegister(arg *gen.RegisterArgumentInfo) (Register, core.ResultList) { @@ -27,6 +27,6 @@ func (r Register) String(ctx *EmulationContext) string { return fmt.Sprintf("%s (#%d)", r.Name, r.Value(ctx)) } -func (r Register) Declaration() core.UnmanagedSourceView { +func (r Register) Declaration() *core.UnmanagedSourceView { return r.declaration }