Initial support for builtin functions. (#3803)

For now, a builtin function is defined by specifying a string literal
initializer in a function declaration:

```carbon
fn MyBuiltin(a: i32) -> i32 = "builtin.name";
```

End-to-end support is included for a sample `"int.add"` builtin
performing integer addition, covering constant evaluation and code
generation.

The implementation here needs substantial refactoring before we'll be
ready to start adding more builtins. That refactoring work will be
coming next. This change is aiming to checkpoint some incremental
progress.
This commit is contained in:
Richard Smith
2024-03-21 20:46:34 +00:00
committed by GitHub
parent 8907948242
commit f0e940ddfd
43 changed files with 1588 additions and 86 deletions
@@ -103,22 +103,22 @@ fn Main() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Run0.ref.loc18: <function> = name_ref Run0, file.%Run0 [template = file.%Run0]
// CHECK:STDOUT: %.loc18_8: i32 = int_literal 1 [template = constants.%.1]
// CHECK:STDOUT: %.loc18_7: init () = call %Run0.ref.loc18(<invalid>)
// CHECK:STDOUT: %.loc18_7: init () = call %Run0.ref.loc18(<invalid>) [template = <error>]
// CHECK:STDOUT: %Run0.ref.loc25: <function> = name_ref Run0, file.%Run0 [template = file.%Run0]
// CHECK:STDOUT: %.loc25_8: i32 = int_literal 0 [template = constants.%.3]
// CHECK:STDOUT: %.loc25_11: i32 = int_literal 1 [template = constants.%.1]
// CHECK:STDOUT: %.loc25_7: init () = call %Run0.ref.loc25(<invalid>)
// CHECK:STDOUT: %.loc25_7: init () = call %Run0.ref.loc25(<invalid>) [template = <error>]
// CHECK:STDOUT: %Run1.ref.loc33: <function> = name_ref Run1, file.%Run1 [template = file.%Run1]
// CHECK:STDOUT: %.loc33: init () = call %Run1.ref.loc33(<invalid>)
// CHECK:STDOUT: %.loc33: init () = call %Run1.ref.loc33(<invalid>) [template = <error>]
// CHECK:STDOUT: %Run1.ref.loc40: <function> = name_ref Run1, file.%Run1 [template = file.%Run1]
// CHECK:STDOUT: %.loc40_8: i32 = int_literal 0 [template = constants.%.3]
// CHECK:STDOUT: %.loc40_11: i32 = int_literal 1 [template = constants.%.1]
// CHECK:STDOUT: %.loc40_7: init () = call %Run1.ref.loc40(<invalid>)
// CHECK:STDOUT: %.loc40_7: init () = call %Run1.ref.loc40(<invalid>) [template = <error>]
// CHECK:STDOUT: %Run2.ref.loc48: <function> = name_ref Run2, file.%Run2 [template = file.%Run2]
// CHECK:STDOUT: %.loc48: init () = call %Run2.ref.loc48(<invalid>)
// CHECK:STDOUT: %.loc48: init () = call %Run2.ref.loc48(<invalid>) [template = <error>]
// CHECK:STDOUT: %Run2.ref.loc55: <function> = name_ref Run2, file.%Run2 [template = file.%Run2]
// CHECK:STDOUT: %.loc55_8: i32 = int_literal 0 [template = constants.%.3]
// CHECK:STDOUT: %.loc55_7: init () = call %Run2.ref.loc55(<invalid>)
// CHECK:STDOUT: %.loc55_7: init () = call %Run2.ref.loc55(<invalid>) [template = <error>]
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -44,7 +44,7 @@ fn F() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %G.ref: <function> = name_ref G, file.%G [template = file.%G]
// CHECK:STDOUT: %.loc16_5: f64 = real_literal 10e-1 [template = constants.%.1]
// CHECK:STDOUT: %.loc16_4: init () = call %G.ref(<invalid>)
// CHECK:STDOUT: %.loc16_4: init () = call %G.ref(<invalid>) [template = <error>]
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT: