Skip to content

Commit

Permalink
Now supports declaring explicit register type not on first sight
Browse files Browse the repository at this point in the history
  • Loading branch information
RealA10N committed Feb 8, 2025
1 parent f644df5 commit e6dc264
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 15 deletions.
23 changes: 23 additions & 0 deletions gen/function_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type FunctionGenerator struct {
ParameterGenerator FunctionContextGenerator[parse.ParameterNode, *RegisterInfo]
LabelDefinitionGenerator LabelContextGenerator[parse.LabelNode, *LabelInfo]
ReferencedTypeGenerator FileContextGenerator[parse.TypeNode, ReferencedTypeInfo]
TargetGenerator FunctionContextGenerator[parse.TargetNode, *TargetInfo]
}

func NewFunctionGenerator() FileContextGenerator[parse.FunctionNode, *FunctionInfo] {
Expand All @@ -25,6 +26,7 @@ func NewFunctionGenerator() FileContextGenerator[parse.FunctionNode, *FunctionIn
ParameterGenerator: NewParameterGenerator(),
LabelDefinitionGenerator: NewLabelDefinitionGenerator(),
ReferencedTypeGenerator: NewReferencedTypeGenerator(),
TargetGenerator: NewTargetGenerator(),
},
)
}
Expand Down Expand Up @@ -94,10 +96,31 @@ func (g *FunctionGenerator) collectLabelDefinitions(
return labelToInstructionIndex, results
}

// Before actually generating the instructions, we iterate over instruction and
// only collect information about target registers.
// Since USM requires all registers to be defined at least once with an explicit
// type, after collecting all register definitions the register manager should
// contain all registers with the required information.
func (g *FunctionGenerator) collectRegisterDefinitions(
ctx *FunctionGenerationContext,
instructions []parse.InstructionNode,
) (results core.ResultList) {
for _, instruction := range instructions {
for _, target := range instruction.Targets {
_, curResults := g.TargetGenerator.Generate(ctx, target)
results.Extend(&curResults)
}
}

return results
}

func (g *FunctionGenerator) generateInstructions(
ctx *FunctionGenerationContext,
instNodes []parse.InstructionNode,
) ([]*InstructionInfo, core.ResultList) {
g.collectRegisterDefinitions(ctx, instNodes)

instructions := make([]*InstructionInfo, 0, len(instNodes))

for _, instNode := range instNodes {
Expand Down
15 changes: 15 additions & 0 deletions gen/function_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,18 @@ func TestNoExplicitRegisterType(t *testing.T) {
details := results.Head.Value
assert.Contains(t, details[0].Message, "untyped register")
}

func TestExplicitRegisterDefinitionNotOnSecondSight(t *testing.T) {
src := `func @main {
%a = ADD $32 #0 $32 #0
$32 %a = ADD %a $32 #1
RET
}`
function, results := generateFunctionFromSource(t, src)
assert.True(t, results.IsEmpty())
assert.NotNil(t, function)

a := function.Registers.GetRegister("%a")
assert.NotNil(t, a)
assert.Equal(t, "$32", a.Type.String())
}
7 changes: 5 additions & 2 deletions gen/instruction_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

type InstructionGenerator struct {
ArgumentGenerator InstructionContextGenerator[parse.ArgumentNode, ArgumentInfo]
TargetGenerator InstructionContextGenerator[parse.TargetNode, *TargetInfo]
TargetGenerator FunctionContextGenerator[parse.TargetNode, *TargetInfo]
}

func NewInstructionGenerator() FunctionContextGenerator[
Expand Down Expand Up @@ -54,7 +54,10 @@ func (g *InstructionGenerator) generateTargets(

for i, target := range node.Targets {
v := target.View()
targetInfo, curResults := g.TargetGenerator.Generate(ctx, target)
targetInfo, curResults := g.TargetGenerator.Generate(
ctx.FunctionGenerationContext,
target,
)
results.Extend(&curResults)

if targetInfo.Register == nil {
Expand Down
6 changes: 3 additions & 3 deletions gen/target_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ type TargetGenerator struct {
ReferencedTypeGenerator FileContextGenerator[parse.TypeNode, ReferencedTypeInfo]
}

func NewTargetGenerator() InstructionContextGenerator[parse.TargetNode, *TargetInfo] {
return InstructionContextGenerator[parse.TargetNode, *TargetInfo](
func NewTargetGenerator() FunctionContextGenerator[parse.TargetNode, *TargetInfo] {
return FunctionContextGenerator[parse.TargetNode, *TargetInfo](
&TargetGenerator{
ReferencedTypeGenerator: NewReferencedTypeGenerator(),
},
Expand Down Expand Up @@ -42,7 +42,7 @@ func NewRegisterTypeMismatchResult(
// If the targe node does not have an explicit type, and the register has not
// been defined and processed yet, the generator will return nil.
func (g *TargetGenerator) Generate(
ctx *InstructionGenerationContext,
ctx *FunctionGenerationContext,
node parse.TargetNode,
) (*TargetInfo, core.ResultList) {
registerName := nodeToSourceString(ctx.FileGenerationContext, node.Register)
Expand Down
17 changes: 7 additions & 10 deletions gen/target_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,17 @@ func TestTargetRegisterAlreadyDefined(t *testing.T) {
"%a": &gen.RegisterInfo{Name: "%a", Type: intTypeRef},
}

ctx := gen.InstructionGenerationContext{
FunctionGenerationContext: &gen.FunctionGenerationContext{
FileGenerationContext: &gen.FileGenerationContext{
GenerationContext: &testGenerationContext,
SourceContext: src.Ctx(),
Types: &types,
},
Registers: &registers,
ctx := &gen.FunctionGenerationContext{
FileGenerationContext: &gen.FileGenerationContext{
GenerationContext: &testGenerationContext,
SourceContext: src.Ctx(),
Types: &types,
},
InstructionInfo: gen.NewEmptyInstructionInfo(&unmanaged),
Registers: &registers,
}

generator := gen.NewTargetGenerator()
info, results := generator.Generate(&ctx, node)
info, results := generator.Generate(ctx, node)
assert.True(t, results.IsEmpty())
assert.Equal(t, intType, info.Register.Type.Base)
}

0 comments on commit e6dc264

Please sign in to comment.