@@ -3,13 +3,17 @@ use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericAr
3
3
use rustc_ast:: ast:: * ;
4
4
use rustc_ast:: attr;
5
5
use rustc_ast:: ptr:: P as AstP ;
6
+ use rustc_data_structures:: fx:: FxHashMap ;
6
7
use rustc_data_structures:: stack:: ensure_sufficient_stack;
7
8
use rustc_data_structures:: thin_vec:: ThinVec ;
8
9
use rustc_errors:: struct_span_err;
9
10
use rustc_hir as hir;
10
11
use rustc_hir:: def:: Res ;
11
12
use rustc_span:: source_map:: { respan, DesugaringKind , Span , Spanned } ;
12
13
use rustc_span:: symbol:: { sym, Ident , Symbol } ;
14
+ use rustc_target:: asm;
15
+ use std:: collections:: hash_map:: Entry ;
16
+ use std:: fmt:: Write ;
13
17
14
18
impl < ' hir > LoweringContext < ' _ , ' hir > {
15
19
fn lower_exprs ( & mut self , exprs : & [ AstP < Expr > ] ) -> & ' hir [ hir:: Expr < ' hir > ] {
@@ -175,7 +179,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
175
179
let e = e. as_ref ( ) . map ( |x| self . lower_expr ( x) ) ;
176
180
hir:: ExprKind :: Ret ( e)
177
181
}
178
- ExprKind :: LlvmInlineAsm ( ref asm) => self . lower_expr_asm ( asm) ,
182
+ ExprKind :: InlineAsm ( ref asm) => self . lower_expr_asm ( e. span , asm) ,
183
+ ExprKind :: LlvmInlineAsm ( ref asm) => self . lower_expr_llvm_asm ( asm) ,
179
184
ExprKind :: Struct ( ref path, ref fields, ref maybe_expr) => {
180
185
let maybe_expr = maybe_expr. as_ref ( ) . map ( |x| self . lower_expr ( x) ) ;
181
186
hir:: ExprKind :: Struct (
@@ -968,7 +973,294 @@ impl<'hir> LoweringContext<'_, 'hir> {
968
973
result
969
974
}
970
975
971
- fn lower_expr_asm ( & mut self , asm : & LlvmInlineAsm ) -> hir:: ExprKind < ' hir > {
976
+ fn lower_expr_asm ( & mut self , sp : Span , asm : & InlineAsm ) -> hir:: ExprKind < ' hir > {
977
+ let asm_arch = if let Some ( asm_arch) = self . sess . asm_arch {
978
+ asm_arch
979
+ } else {
980
+ struct_span_err ! ( self . sess, sp, E0472 , "asm! is unsupported on this target" ) . emit ( ) ;
981
+ return hir:: ExprKind :: Err ;
982
+ } ;
983
+
984
+ // Lower operands to HIR, filter_map skips any operands with invalid
985
+ // register classes.
986
+ let sess = self . sess ;
987
+ let operands: Vec < _ > = asm
988
+ . operands
989
+ . iter ( )
990
+ . filter_map ( |( op, op_sp) | {
991
+ let lower_reg = |reg| {
992
+ Some ( match reg {
993
+ InlineAsmRegOrRegClass :: Reg ( s) => asm:: InlineAsmRegOrRegClass :: Reg (
994
+ asm:: InlineAsmReg :: parse (
995
+ asm_arch,
996
+ |feature| {
997
+ self . sess . target_features . contains ( & Symbol :: intern ( feature) )
998
+ } ,
999
+ s,
1000
+ )
1001
+ . map_err ( |e| {
1002
+ let msg = format ! ( "invalid register `{}`: {}" , s. as_str( ) , e) ;
1003
+ sess. struct_span_err ( * op_sp, & msg) . emit ( ) ;
1004
+ } )
1005
+ . ok ( ) ?,
1006
+ ) ,
1007
+ InlineAsmRegOrRegClass :: RegClass ( s) => {
1008
+ asm:: InlineAsmRegOrRegClass :: RegClass (
1009
+ asm:: InlineAsmRegClass :: parse ( asm_arch, s)
1010
+ . map_err ( |e| {
1011
+ let msg = format ! (
1012
+ "invalid register class `{}`: {}" ,
1013
+ s. as_str( ) ,
1014
+ e
1015
+ ) ;
1016
+ sess. struct_span_err ( * op_sp, & msg) . emit ( ) ;
1017
+ } )
1018
+ . ok ( ) ?,
1019
+ )
1020
+ }
1021
+ } )
1022
+ } ;
1023
+ let op = match op {
1024
+ InlineAsmOperand :: In { reg, expr } => hir:: InlineAsmOperand :: In {
1025
+ reg : lower_reg ( * reg) ?,
1026
+ expr : self . lower_expr_mut ( expr) ,
1027
+ } ,
1028
+ InlineAsmOperand :: Out { reg, late, expr } => hir:: InlineAsmOperand :: Out {
1029
+ reg : lower_reg ( * reg) ?,
1030
+ late : * late,
1031
+ expr : expr. as_ref ( ) . map ( |expr| self . lower_expr_mut ( expr) ) ,
1032
+ } ,
1033
+ InlineAsmOperand :: InOut { reg, late, expr } => hir:: InlineAsmOperand :: InOut {
1034
+ reg : lower_reg ( * reg) ?,
1035
+ late : * late,
1036
+ expr : self . lower_expr_mut ( expr) ,
1037
+ } ,
1038
+ InlineAsmOperand :: SplitInOut { reg, late, in_expr, out_expr } => {
1039
+ hir:: InlineAsmOperand :: SplitInOut {
1040
+ reg : lower_reg ( * reg) ?,
1041
+ late : * late,
1042
+ in_expr : self . lower_expr_mut ( in_expr) ,
1043
+ out_expr : out_expr. as_ref ( ) . map ( |expr| self . lower_expr_mut ( expr) ) ,
1044
+ }
1045
+ }
1046
+ InlineAsmOperand :: Const { expr } => {
1047
+ hir:: InlineAsmOperand :: Const { expr : self . lower_expr_mut ( expr) }
1048
+ }
1049
+ InlineAsmOperand :: Sym { expr } => {
1050
+ hir:: InlineAsmOperand :: Sym { expr : self . lower_expr_mut ( expr) }
1051
+ }
1052
+ } ;
1053
+ Some ( op)
1054
+ } )
1055
+ . collect ( ) ;
1056
+
1057
+ // Stop if there were any errors when lowering the register classes
1058
+ if operands. len ( ) != asm. operands . len ( ) {
1059
+ return hir:: ExprKind :: Err ;
1060
+ }
1061
+
1062
+ // Validate template modifiers against the register classes for the operands
1063
+ for p in & asm. template {
1064
+ if let asm:: InlineAsmTemplatePiece :: Placeholder {
1065
+ operand_idx,
1066
+ modifier : Some ( modifier) ,
1067
+ span : placeholder_span,
1068
+ } = * p
1069
+ {
1070
+ let op_sp = asm. operands [ operand_idx] . 1 ;
1071
+ match & operands[ operand_idx] {
1072
+ hir:: InlineAsmOperand :: In { reg, .. }
1073
+ | hir:: InlineAsmOperand :: Out { reg, .. }
1074
+ | hir:: InlineAsmOperand :: InOut { reg, .. }
1075
+ | hir:: InlineAsmOperand :: SplitInOut { reg, .. } => {
1076
+ let class = reg. reg_class ( ) ;
1077
+ let valid_modifiers = class. valid_modifiers ( asm_arch) ;
1078
+ if !valid_modifiers. contains ( & modifier) {
1079
+ let mut err = sess. struct_span_err (
1080
+ placeholder_span,
1081
+ "invalid asm template modifier for this register class" ,
1082
+ ) ;
1083
+ err. span_label ( placeholder_span, "template modifier" ) ;
1084
+ err. span_label ( op_sp, "argument" ) ;
1085
+ if !valid_modifiers. is_empty ( ) {
1086
+ let mut mods = format ! ( "`{}`" , valid_modifiers[ 0 ] ) ;
1087
+ for m in & valid_modifiers[ 1 ..] {
1088
+ let _ = write ! ( mods, ", `{}`" , m) ;
1089
+ }
1090
+ err. note ( & format ! (
1091
+ "the `{}` register class supports \
1092
+ the following template modifiers: {}",
1093
+ class. name( ) ,
1094
+ mods
1095
+ ) ) ;
1096
+ } else {
1097
+ err. note ( & format ! (
1098
+ "the `{}` register class does not support template modifiers" ,
1099
+ class. name( )
1100
+ ) ) ;
1101
+ }
1102
+ err. emit ( ) ;
1103
+ }
1104
+ }
1105
+ hir:: InlineAsmOperand :: Const { .. } => {
1106
+ let mut err = sess. struct_span_err (
1107
+ placeholder_span,
1108
+ "asm template modifiers are not allowed for `const` arguments" ,
1109
+ ) ;
1110
+ err. span_label ( placeholder_span, "template modifier" ) ;
1111
+ err. span_label ( op_sp, "argument" ) ;
1112
+ err. emit ( ) ;
1113
+ }
1114
+ hir:: InlineAsmOperand :: Sym { .. } => {
1115
+ let mut err = sess. struct_span_err (
1116
+ placeholder_span,
1117
+ "asm template modifiers are not allowed for `sym` arguments" ,
1118
+ ) ;
1119
+ err. span_label ( placeholder_span, "template modifier" ) ;
1120
+ err. span_label ( op_sp, "argument" ) ;
1121
+ err. emit ( ) ;
1122
+ }
1123
+ }
1124
+ }
1125
+ }
1126
+
1127
+ let mut used_input_regs = FxHashMap :: default ( ) ;
1128
+ let mut used_output_regs = FxHashMap :: default ( ) ;
1129
+ for ( idx, op) in operands. iter ( ) . enumerate ( ) {
1130
+ let op_sp = asm. operands [ idx] . 1 ;
1131
+ if let Some ( reg) = op. reg ( ) {
1132
+ // Validate register classes against currently enabled target
1133
+ // features. We check that at least one type is available for
1134
+ // the current target.
1135
+ let reg_class = reg. reg_class ( ) ;
1136
+ let mut required_features = vec ! [ ] ;
1137
+ for & ( _, feature) in reg_class. supported_types ( asm_arch) {
1138
+ if let Some ( feature) = feature {
1139
+ if self . sess . target_features . contains ( & Symbol :: intern ( feature) ) {
1140
+ required_features. clear ( ) ;
1141
+ break ;
1142
+ } else {
1143
+ required_features. push ( feature) ;
1144
+ }
1145
+ } else {
1146
+ required_features. clear ( ) ;
1147
+ break ;
1148
+ }
1149
+ }
1150
+ required_features. sort ( ) ;
1151
+ required_features. dedup ( ) ;
1152
+ match & required_features[ ..] {
1153
+ [ ] => { }
1154
+ [ feature] => {
1155
+ let msg = format ! (
1156
+ "register class `{}` requires the `{}` target feature" ,
1157
+ reg_class. name( ) ,
1158
+ feature
1159
+ ) ;
1160
+ sess. struct_span_err ( op_sp, & msg) . emit ( ) ;
1161
+ }
1162
+ features => {
1163
+ let msg = format ! (
1164
+ "register class `{}` requires at least one target feature: {}" ,
1165
+ reg_class. name( ) ,
1166
+ features. join( ", " )
1167
+ ) ;
1168
+ sess. struct_span_err ( op_sp, & msg) . emit ( ) ;
1169
+ }
1170
+ }
1171
+
1172
+ // Check for conflicts between explicit register operands.
1173
+ if let asm:: InlineAsmRegOrRegClass :: Reg ( reg) = reg {
1174
+ let ( input, output) = match op {
1175
+ hir:: InlineAsmOperand :: In { .. } => ( true , false ) ,
1176
+ // Late output do not conflict with inputs, but normal outputs do
1177
+ hir:: InlineAsmOperand :: Out { late, .. } => ( !late, true ) ,
1178
+ hir:: InlineAsmOperand :: InOut { .. }
1179
+ | hir:: InlineAsmOperand :: SplitInOut { .. } => ( true , true ) ,
1180
+ hir:: InlineAsmOperand :: Const { .. } | hir:: InlineAsmOperand :: Sym { .. } => {
1181
+ unreachable ! ( )
1182
+ }
1183
+ } ;
1184
+
1185
+ // Flag to output the error only once per operand
1186
+ let mut skip = false ;
1187
+ reg. overlapping_regs ( |r| {
1188
+ let mut check = |used_regs : & mut FxHashMap < asm:: InlineAsmReg , usize > ,
1189
+ input| {
1190
+ match used_regs. entry ( r) {
1191
+ Entry :: Occupied ( o) => {
1192
+ if !skip {
1193
+ skip = true ;
1194
+
1195
+ let idx2 = * o. get ( ) ;
1196
+ let op2 = & operands[ idx2] ;
1197
+ let op_sp2 = asm. operands [ idx2] . 1 ;
1198
+ let reg2 = match op2. reg ( ) {
1199
+ Some ( asm:: InlineAsmRegOrRegClass :: Reg ( r) ) => r,
1200
+ _ => unreachable ! ( ) ,
1201
+ } ;
1202
+
1203
+ let msg = format ! (
1204
+ "register `{}` conflicts with register `{}`" ,
1205
+ reg. name( ) ,
1206
+ reg2. name( )
1207
+ ) ;
1208
+ let mut err = sess. struct_span_err ( op_sp, & msg) ;
1209
+ err. span_label (
1210
+ op_sp,
1211
+ & format ! ( "register `{}`" , reg. name( ) ) ,
1212
+ ) ;
1213
+ err. span_label (
1214
+ op_sp2,
1215
+ & format ! ( "register `{}`" , reg2. name( ) ) ,
1216
+ ) ;
1217
+
1218
+ match ( op, op2) {
1219
+ (
1220
+ hir:: InlineAsmOperand :: In { .. } ,
1221
+ hir:: InlineAsmOperand :: Out { late, .. } ,
1222
+ )
1223
+ | (
1224
+ hir:: InlineAsmOperand :: Out { late, .. } ,
1225
+ hir:: InlineAsmOperand :: In { .. } ,
1226
+ ) => {
1227
+ assert ! ( !* late) ;
1228
+ let out_op_sp = if input { op_sp2 } else { op_sp } ;
1229
+ let msg = & format ! (
1230
+ "use `lateout` instead of \
1231
+ `out` to avoid conflict"
1232
+ ) ;
1233
+ err. span_help ( out_op_sp, msg) ;
1234
+ }
1235
+ _ => { }
1236
+ }
1237
+
1238
+ err. emit ( ) ;
1239
+ }
1240
+ }
1241
+ Entry :: Vacant ( v) => {
1242
+ v. insert ( idx) ;
1243
+ }
1244
+ }
1245
+ } ;
1246
+ if input {
1247
+ check ( & mut used_input_regs, true ) ;
1248
+ }
1249
+ if output {
1250
+ check ( & mut used_output_regs, false ) ;
1251
+ }
1252
+ } ) ;
1253
+ }
1254
+ }
1255
+ }
1256
+
1257
+ let operands = self . arena . alloc_from_iter ( operands) ;
1258
+ let template = self . arena . alloc_from_iter ( asm. template . iter ( ) . cloned ( ) ) ;
1259
+ let hir_asm = hir:: InlineAsm { template, operands, options : asm. options } ;
1260
+ hir:: ExprKind :: InlineAsm ( self . arena . alloc ( hir_asm) )
1261
+ }
1262
+
1263
+ fn lower_expr_llvm_asm ( & mut self , asm : & LlvmInlineAsm ) -> hir:: ExprKind < ' hir > {
972
1264
let inner = hir:: LlvmInlineAsmInner {
973
1265
inputs : asm. inputs . iter ( ) . map ( |& ( c, _) | c) . collect ( ) ,
974
1266
outputs : asm
0 commit comments